Djangoでログイン機能を作る

今回はDjangoにもともと用意されている機能だけでログイン機能(ユーザー認証)を実装してみようと思います。

環境

python 3.6.3 Django 2.0.8

プロジェクトの作成

まずは、Djangoのプロジェクトを作るところから始めましょう。
myprojectという名前のプロジェクトを作成します。
適当なディレクトリに移動して

django-admin.py startproject myproject

これで以下のような構成のファイル群が出来上がります。

./myproject
├── manage.py
└── myproject
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

アプリケーションの作成

続いてログイン機能用にアプリケーションaccountsを作成します。
myprojectのディレクトリに移動します。
移動したディレクトリで

python manage.py startapp accounts

これを実行すると

accounts
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

が出来上がります。

ここまで出来たらaccountsの中にurls.pyforms.pyを足しましょう。
中身は後述します。

accounts
├── __init__.py
├── admin.py
├── apps.py
├── forms.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
├── urls.py
└── views.py

こんな感じになっていれば正解です。

一度./myprojectに戻ります。
./myproject/myproject/settings.pyのINSTALLED_APPSに以下のように追記します。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'accounts.apps.AccountsConfig', # 追記
]

./myproject/myproject/urls.pyにも以下のように追記します。

from django.contrib import admin
from django.urls import path,include # include を追記

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/',include('accounts.urls')), # 追記
]

ここまで出来たら次のコマンドを実行します。

python manage.py makemigrations

出力

No changes detected
python manage.py migrate

出力

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying sessions.0001_initial... OK

次はいよいよログイン機能を作っていこうと思います。

ログイン機能を作る

ログインページの準備

Djangoの標準のログインページを利用してもよいのですが、大体の人はカスタマイズしたいと思うので、ログインページを自作していきましょう。
/myproject/accounts/templates/accountslogin.htmllogout.htmlを作ります。
それに加えてログインが成功したとき用のindex.htmlを作成します。
それぞれの中身は以下の通りです。
login.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>LOGIN</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <form action="" method="POST">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">ログイン</button>
    </form>
</body>
</html>

logout.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>LOGOUT</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="" method="POST">
{% csrf_token %}
<button type="submit">ログアウト</button>
</form>
</body>
</html>

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>index</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>トップページ</p>
<a href="{% url 'logout' %}">ログアウト</a>
</body>
</html>

forms.pyの準備

./myproject/accounts/forms.pyの中身は以下のような感じ

from django.contrib.auth import forms as auth_forms

class LoginForm(auth_forms.AuthenticationForm):
    '''ログインフォーム'''
    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)
        for field in self.fields.values():
            field.widget.attrs['placeholder'] = field.label

views.pyの準備

./myproject/accounts/views.pyの中身は以下のような感じ

from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
from . import forms

class MyLoginView(LoginView):
    form_class = forms.LoginForm
    template_name = "accounts/login.html"

class MyLogoutView(LoginRequiredMixin, LogoutView):
    template_name = "accounts/logout.html"

class IndexView(TemplateView):
    template_name = "accounts/index.html"

urls.pyの準備

./myproject/accounts/urls.pyの中身は以下のような感じ

from django.urls import path
from . import views
urlpatterns = [
    path('login/', views.MyLoginView.as_view(), name="login"),
    path('logout/', views.MyLogoutView.as_view(), name="logout"),
    path('index/',views.IndexView.as_view(), name="index")
]

settings.pyの準備

./myproject/myproject/settings.pyの最後に以下を追記します。

LOGIN_URL = 'login' # ログインしていないときのリダイレクト先
LOGIN_REDIRECT_URL = 'index' # ログイン後のリダイレクト先
LOGOUT_REDIRECT_URL = 'index' # ログアウト後のリダイレクト先

ここまで出来たら

python manage.py createsuperuser

でアカウントを作成しましょう。

python manage.py runserver

でサーバーを起動してhttp://localhost:8000/accounts/login/にアクセスして先ほど作成したアカウントでログインできるか確認しましょう。
ログインができれば成功です。

ユーザーの新規作成ページ

続いてwebページ上でアカウントの作成ができるように改造していきましょう。

template/accounts/create.htmlを新たに作成

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>CREATE</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <p>新規ユーザーの作成</p>
  <form action="" method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">作成</button>
  </form>
</body>
</html>

./myproject/accounts/views.pyに追記

from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView,CreateView # 追記
from django.contrib.auth.forms import UserCreationForm  # 追記
from django.urls import reverse_lazy # 追記
from . import forms

class MyLoginView(LoginView):
    form_class = forms.LoginForm
    template_name = "accounts/login.html"

class MyLogoutView(LoginRequiredMixin, LogoutView):
    template_name = "accounts/logout.html"

class IndexView(TemplateView):
    template_name = "accounts/index.html"

# 追記
class UserCreateView(CreateView):
    form_class = UserCreationForm
    template_name = "accounts/create.html"
    success_url = reverse_lazy("login")

./myproject/accounts/urls.pyにも追記

from django.urls import path
from . import views
urlpatterns = [
    path('login/', views.MyLoginView.as_view(), name="login"),
    path('logout/', views.MyLogoutView.as_view(), name="logout"),
    path('index/', views.IndexView.as_view(), name="index"),
    path('create/', views.UserCreateView.as_view(),name="create"), # 追記
]

これでサーバーを起動してhttp://localhost:8000/accounts/create/にアクセスすればユーザーの新規作成画面が表示されるはずです。

表示出来たらユーザーを作ってみましょう。

ユーザーを作成したらログインができるかも確認してみましょう。