Django ユーザのログイン・ログアウト機能の実装

初めに

前回に続いて本棚アプリケーションの作成を行いました。今回はユーザのログイン・ログアウト機能の実装を行いました。
これに対して行った具体的な手順をまとめます。
nissin-geppox.hatenablog.com

概要

  • ログイン機能の実装
  • ログアウト機能の実装
  • アプリケーションaccountsの作成
  • 会員登録機能の実装

ログイン機能の実装

まず初めに、ログイン・ログアウト機能の実装に際してルーティングの設定をurls.pyに対して以下のような変更を行いました。

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('django.contrib.auth.urls')),
    path('', include('book.urls'))
]

次に、ログイン画面用のhtmlを作成します。
以下のコマンドよりhtmlファイルを生成しました。

$ mkdir templates/registration
$ touch templates/registration/login.html

次に、生成したlogin.htmlに以下のようなコードを追加しました。

{% extends 'base.html' %}

{% block content %}
<h1>ログイン</h1>
<form method="post" class="p-4 m-4 bg-light border border-success rounded form-group">
  {% csrf_token %}
  {% for error in form.errors.values %}
  {{ error }}
  {% endfor %}
  <label>
    ユーザID
  </label>
  <input class="form-control" name="username">
  <label>
    パスワード
  </label>
  <input type="password" class="form-control" name="password">
  <button type="submit" class="btn btn-success mt-4">ログインする</button>
</form>
{% endblock %}

また、以下のようにログイン完了時のURLの設定をsetting.pyにて行いました。

-- 一部省略 --

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

LOGIN_REDIRECT_URL ='list-book'

以下の画像は作成したログイン画面の様子です。

上の画像より、作成したログイン画面が正常に表示されることを確認することができました。

また、以下の画像はまだ登録をしていないユーザを入力し、ログインを試みたときの様子です。

上の画像より、たしかに、登録したユーザしかログインできないことを確認することができました。

ログアウト機能の実装

続いて、ログアウト機能を実装しました。
まず、以下のようにurls.pyに対してルーティングの設定を行いました。

from django.urls import path
from . import views
urlpatterns = [
  path('', views.index_view, name='index'),
  path('book/', views.ListBookView.as_view(), name='list-book'),
  path('book/<int:pk>/detail/', views.DetailBookView.as_view(), name='detail-book'),
  path('book/create/', views.CreateBookView.as_view(), name='create-book'),
  path('book/<int:pk>/delete/', views.DeleteBookView.as_view(), name='delete-book'),
  path('book/<int:pk>/update/', views.UpdateBookView.as_view(), name='update-book'),
  path('logout/', views.logout_view, name='logout'),

次に、以下のようにログアウトとredirect機能をviews.pyに追加しました。

from django.shortcuts import render, redirect
from django.contrib.auth import logout
from django.urls import reverse_lazy
from django.views.generic import (
  ListView,
  DetailView,
  CreateView,
  DeleteView,
  UpdateView,
)
from .models import Book

-- 一部省略 --

  return render(request, 'book/index.html',{'object_list': object_list})

def logout_view(request):
  logout(request)
  return redirect('index')

続いて、以下のようにログアウトのリンクをbase.htmlに追加しました。

-- 一部省略 --

<body>
  <nav class="navbar navbar-dark bg-success sticky-top">
    <div class="navbar-nav d-flex flex-row">
      <a class="nav-link mx-3" href="{% url 'list-book' %}">書籍一覧</a>
      <a class="nav-link mx-3" href="{% url 'create-book' %}">書籍登録</a>
    </div>
    <div class="navbar-nav d-flex flex-row">
      {% if request.user.is_authenticated %}
      <a class="nav-link mx-3" href="{% url 'logout' %}">ログアウト</a>
      {% else %}
      <a class="nav-link mx-3" href="{% url 'login' %}">ログイン</a>
      {% endif %}
    </div>
  </nav>
  <div class="'p-4">
    <h1>{% block h1 %}{% endblock %}</h1>
    {% block content %}{% endblock content %}
  </div>
</body>
</html>

アプリケーションaccountsの作成

続いて、会員登録機能を追加するために以下のコマンドを用いて新たにアプリケーションaccountsを作成しました。

$ python3 manage.py startapp accounts

次に、作成したアプリケーションを反映させるためにsetting.pyに以下のようなコードを追加します。

-- 一部省略 --

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'book.apps.BookConfig',
    'accounts.apps.AccountsConfig',
]

-- 一部省略 --

また、以下のようにbookproject/urls.pyの内容を修正しました。

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

次に、以下のようにbook/urls.pyのlogoutに関する記述を修正しました。

from django.urls import path

from . import views

urlpatterns = [
  path('', views.index_view, name='index'),
  path('book/', views.ListBookView.as_view(), name='list-book'),
  path('book/<int:pk>/detail/', views.DetailBookView.as_view(), name='detail-book'),
  path('book/create/', views.CreateBookView.as_view(), name='create-book'),
  path('book/<int:pk>/delete/', views.DeleteBookView.as_view(), name='delete-book'),
  path('book/<int:pk>/update/', views.UpdateBookView.as_view(), name='update-book'),
]

最後に、views.pyに関しても以下のように修正しました。

from django.shortcuts import render, redirect
from django.urls import reverse_lazy
from django.views.generic import (
  ListView,
  DetailView,
  CreateView,
  DeleteView,
  UpdateView,
)
from .models import Book

-- 一部省略 --

def index_view(request):
  object_list = Book.objects.order_by('category')
  return render(request, 'book/index.html',{'object_list': object_list})

-- 以下を削除 --

会員登録機能の実装

続いて、会員登録機能を実装しました。
まず、以下のコマンドよりurls.pyファイルを生成しました。

$ touch accounts/urls.py

また、生成したurls.pyに以下のようなコードを追加しました。

from django.urls import path
from django.contrib.auth.views import LoginView, LogoutView

from .views import SignupView

app_name = 'accounts'

urlpatterns = [
  path('login/', LoginView.as_view(), name='login'),
  path('logout/', LogoutView.as_view(), name='logout'),
  path('signup/', SignupView.as_view(), name='signup'),
]

次に、以下のようにsetting.pyに対してログアウトしたときの遷移先を設定しました。

-- 一部省略 --

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

LOGIN_REDIRECT_URL ='index'
LOGOUT_REDIRECT_URL ='index'

次に、app_nameで宣言した文字列を以下のようにbase.htmlに反映させました。

-- 一部省略 --

    <div class="navbar-nav d-flex flex-row">
      {% if request.user.is_authenticated %}
      <a class="nav-link mx-3" href="{% url 'accounts:logout' %}">ログアウト</a>
      {% else %}
      <a class="nav-link mx-3" href="{% url 'accounts:login' %}">ログイン</a>
      {% endif %}
    </div>
  </nav>
  <div class="'p-4">
    <h1>{% block h1 %}{% endblock %}</h1>
    {% block content %}{% endblock content %}
  </div>
</body>

</html>

続いて、accountsのviews.pyを以下のように作成しました。

from django.shortcuts import render
from django.contrib.auth.models import User
from django.urls import reverse_lazy
from django.views.generic import CreateView

from .forms import SignupForm

class SignupView(CreateView):
  model = User
  form_class = SignupForm
  template_name = 'accounts/signup.html'
  success_url = reverse_lazy('index')

次に、views.pyで指定したforms.pyを作成します。
まず、以下のコマンドよりforms.pyを生成しました。

$ touch accounts/forms.py

続いて、生成したforms.pyに以下のようなコードを追加しました。

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class SignupForm(UserCreationForm):
  class Meta:
    model = User
    fields = ('username',)

最後に、会員登録画面を作成しました。
まず、以下のコマンドより、会員登録画面用のhtmlを生成しました。

$ signup.html

続いて、生成したsignup.htmlに以下のようなコードを追加しました。

{% extends 'base.html' %}

{% block title %}アカウント作成{% endblock %}
{% block h1 %}アカウント作成{% endblock %}
{% block content %}
<form method="post" class="p-4 m-4 bg-light border border-success rounded form-group">
  {% csrf_token %}
  <input type="text" name='username' class="form-control my-4" placeholder="ユーザ ID">
  <input type="password" name='password1' class="form-control mt-4" placeholder="パスワード">
  <input type="password" name='password2' class="form-control mt-4" placeholder="パスワード確認用">
  <small class="mb-2 d-block text-start">パスワードは8文字以上で設定してください。</small>
  {% if form.errors %}
  <span class="mb-2 small text-danger d-block text-start">利用できないユーザ IDやパスワードの可能性があります。入力内容を再度ご確認ください。</span>
  {% endif %}
  <button type="submit" class="btn btn-success m-2">アカウント作成</button>
</form>
{% endblock %}

加えて、管理画面で会員登録の文字情報が表示されるようにbase.htmlを以下のように変更しました。

-- 一部省略 --

    <div class="navbar-nav d-flex flex-row">
      {% if request.user.is_authenticated %}
      <a class="nav-link mx-3" href="{% url 'accounts:logout' %}">ログアウト</a>
      {% else %}
      <a class="nav-link mx-3" href="{% url 'accounts:login' %}">ログイン</a>
      <a class="nav-link mx-3" href="{% url 'accounts:signup' %}">会員登録</a>
      {% endif %}
    </div>
  </nav>
  <div class="'p-4">
    <h1>{% block h1 %}{% endblock %}</h1>
    {% block content %}{% endblock content %}
  </div>
</body>

</html>

続いて、accountsのviews.pyを以下のように作成しました。

from django.shortcuts import render
from django.contrib.auth.models import User
from django.urls import reverse_lazy
from django.views.generic import CreateView

from .forms import SignupForm

class SignupView(CreateView):
  model = User
  form_class = SignupForm
  template_name = 'accounts/signup.html'
  success_url = reverse_lazy('index')

以下の画像は会員登録画面の様子です。

上の画像より、会員登録画面が正常に表示されることを確認することができました。