Python | Django | class-based viewsにおけるログインの実装方法

2021年8月25日

公開日:2021/8/25
更新日:2021/9/19

Pythonには,DjangoというWebアプリケーションフレームワークがある.フレームワークのため,Djangoを利用するとWebアプリを通常よりも短時間で開発することが可能になる.

class-based viewsは,viewsを実装する手段の1つであり,関数の代わりにPythonのオブジェクトとしてviewsを定義する.viewsの作成とデータの追加・更新・削除が容易になる.

本記事では,「class-based viewsにおけるログインの実装方法」を以下6つの構成にて記す.

  1. プロジェクトとアプリの作成
  2. ユーザー登録処理
  3. ログイン・ログアウト処理1
  4. ログイン・ログアウト処理2
  5. ログインの保持
  6. 反省点
  7. 参照

◆実施環境

Python 3.8.8
Django 3.2.3
VS Code 1.59.0

■class-based viewsにおけるログインの実装方法

  1. プロジェクトとアプリの作成

新たにフォルダを開く.VS Codeの"File"をクリックし,"Open Folder"からフォルダを選ぶ.

今回は"myclassbasedviewslogintest"という名のフォルダを作成したので,選択する.選択後,以下赤枠のようにフォルダが出来上がる.

VS Codeの"View"を開き,"Terminal"をクリックする.VS Codeの下部にターミナルが開くので,”conda activate 仮想環境名”を実行し,仮想環境に移行する(移行方法の詳細はこちら).その後以下のように”django-admin startproject プロジェクト名”を実行する.プロジェクト名は"views_login"にした.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogintest
>django-admin startproject views_login

ターミナルで"cd views_login"を入力し,ディレクトリを変更する.その後,"python manage.py startapp アプリ名"を入力する.アプリ名は"account"にした.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogintest\views_login
>python manage.py startapp account

VS Codeにプロジェクト名"views_login"とアプリ名"account"が以下のように作成された.

“views_login/settings.py"のINSTALLED_APPを以下のように編集する.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'account', # 追記箇所
]

“account/models.py"を以下のように編集する.

from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser, PermissionsMixin,
)
from django.urls import reverse_lazy

class UserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, password=None):
        if not email:
            raise ValueError('You need Email address!')
        user = self.model(
            email=email,
            date_of_birth=date_of_birth,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

class MyUser(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=100)
    email = models.EmailField(max_length=100, unique=True)
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['date_of_birth']

    objects = UserManager()

    def get_absolute_url(self):
        return reverse_lazy('account:top')

“views_login/settings.py"のINSTALLED_APPの下に追記し,以下のように編集する.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'account',
]

AUTH_USER_MODEL = 'account.MyUser' # 追記箇所

以下にてマイグレーションを実施する.ターミナルで"cd views_login"を入力し,ディレクトリを変更する.その後,"python manage.py makemigrations account"を入力する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogintest\views_login
>python manage.py makemigrations account

Migrations for 'account': # 以下出力箇所
account\migrations\0001_initial.py
- Create model MyUser

続けて,ターミナルで"python manage.py migrate"を入力する.以下が出力されれば,成功となる.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogintest\views_login
>python manage.py migrate

Operations to perform: # 以下出力箇所
Apply all migrations: account, admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... 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 auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying account.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying sessions.0001_initial... OK
  1. ユーザー登録処理

“account/views.py"を以下のように編集する.

from django.shortcuts import render
from django.views.generic.edit import CreateView
from django.views.generic.base import TemplateView

class TopView(TemplateView):
    template_name = 'top.html'

class RegistrationView(CreateView):
    template_name = 'registration.html'

“account"に"forms.py"を以下のように作成する.

“account/forms.py"を以下のように編集する.

from django import forms
from .models import MyUser
from django.contrib.auth.password_validation import validate_password

class RegistrationForm(forms.ModelForm):
    username = forms.CharField(label='name')
    date_of_birth = forms.DateField(label='date_of_birth')
    email = forms.EmailField(label='email address')
    password = forms.CharField(label='password', widget=forms.PasswordInput())

    class Meta:
        model = MyUser
        fields = ['username', 'date_of_birth', 'email', 'password']

    def save(self, commit=False):
        user = super().save(commit=False)
        validate_password(self.cleaned_data['password'], user)
        user.set_password(self.cleaned_data['password'])
        user.save()
        return user

“account/views.py"に追記し,以下のように編集する.

from django.shortcuts import render
from django.views.generic.edit import CreateView, FormView # 変更箇所(2~4行目)
from django.views.generic.base import TemplateView, View
from .forms import RegistrationForm

class TopView(TemplateView):
    template_name = 'top.html'

class RegistrationView(CreateView):
    template_name = 'registration.html'
    form_class = RegistrationForm # 以下追記箇所

class MyLoginView(FormView):
    pass

class MyLogoutView(View):
    pass

“account"フォルダに"urls.py"を以下のように作成する.

“account/urls.py"を以下のように編集する.

from django.urls import path
from .views import (
    TopView, RegistrationView,
    MyLoginView, MyLogoutView
)

app_name = 'account'
urlpatterns = [
    path('top/', TopView.as_view(), name='top'),
    path('registration/', RegistrationView.as_view(), name='registration'),
    path('login/', MyLoginView.as_view(), name='login'),
    path('logout/', MyLogoutView.as_view(), name='logout'),
]

“views_login/urls.py"に追記し,以下のように編集する.

from django.contrib import admin
from django.urls import path, include # 変更箇所

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

“views_login/settings.py"に追記し,以下のように編集する.

from pathlib import Path
import os # 追記箇所

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATE_DIR = os.path.join(BASE_DIR, 'templates') # 追記箇所

~省略~

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [TEMPLATE_DIR,], # 変更箇所
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

“views_login"プロジェクトフォルダに"templates"フォルダを作成し,その中に"base.html"を作成する.

以下URLにアクセスし,linkをコピーする.

https://getbootstrap.com/docs/5.0/getting-started/introduction/#css

“templates/base.html"を以下のように編集する.5行目にコピーしたlinkを貼り付けする.

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
  </head>
  <body>
    <nav class="navbar-expand-lg navbar-light bg-light">
      <a class="navbar-brand" href="{% url 'account:top' %}">&nbsp;Top</a>
      {% if user.is_authenticated %}
      <a class="navbar-brand" href="{% url 'account:logout' %}">Logout</a>
      {% else %}
      <a class="navbar-brand" href="{% url 'account:login' %}">Login</a>
      <a class="navbar-brand" href="{% url 'account:registration' %}">Registration</a>
      {% endif %}
    </nav>
    {% block content %}{% endblock %}
  </body>
</html>

“templates"フォルダに"top.html"と"registration.html"を以下のように作成する.

“top.html"を以下のように編集する.

{% extends 'base.html' %}
{% block content %}
<h2><p>&nbsp;Hello World!</p></h2>
<h2><p>&nbsp;This is Top Page!</p></h2>
{% endblock %}

“registration.html"を以下のように編集する.

{% extends 'base.html' %}
{% block content %}
<form method="POST">
  {% csrf_token %}
  {{ form.as_p }}
  <input type="submit" value="Registration">
</form>
{% endblock %}

VS Codeのターミナルで,”conda activate 仮想環境名”を実行し,ターミナルで"cd views_login"(プロジェクト名)を入力し,ディレクトリを変更する.変更後,以下のように”python manage.py runserver”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewtest\class_based_view
>python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced). # 以下出力箇所
August 24, 2021 - 15:49:19
Django version 3.2.3, using settings 'class_based_view.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

上記の"http://127.0.0.1:8000/"をクリックすると,ブラウザが開き,以下画面が出力される.

ブラウザのURLに"http://127.0.0.1:8000/account/top"と入力すると,以下トップページに遷移する."Registration"をクリックする.

以下画面に遷移する.

以下ページで以下のように記述し,"Registration"ボタンをクリックする.

問題がなければ,以下トップページに遷移する.

VS Codeにおいて,SQLiteをインストールし(詳細はこちら参照),"SQLITE EXPLORER"を開くと,"account_myuser"テーブルを以下のように確認できる.

“account_myuser"テーブルを右クリックし,"Show Table"をクリックすると以下のように上記で記述したユーザー内容を確認することができる.

  1. ログイン・ログアウト処理1

“account/forms.py"に追記し,以下のように編集する.

from django import forms
from .models import MyUser
from django.contrib.auth.password_validation import validate_password

class RegistrationForm(forms.ModelForm):
    username = forms.CharField(label='name')
    date_of_birth = forms.DateField(label='date_of_birth')
    email = forms.EmailField(label='email address')
    password = forms.CharField(label='password', widget=forms.PasswordInput())

    class Meta:
        model = MyUser
        fields = ['username', 'date_of_birth', 'email', 'password']

    def save(self, commit=False):
        user = super().save(commit=False)
        validate_password(self.cleaned_data['password'], user)
        user.set_password(self.cleaned_data['password'])
        user.save()
        return user

class LoginForm(forms.Form): # 以下追記箇所
    email = forms.EmailField(label='email address')
    password = forms.CharField(label='password', widget=forms.PasswordInput())

“account/views.py"に追記し,以下のように編集する.

from django.shortcuts import render, redirect # 変更箇所
from django.views.generic.edit import CreateView, FormView
from django.views.generic.base import TemplateView, View
from .forms import RegistrationForm, LoginForm # 変更箇所
from django.contrib.auth import authenticate, login, logout # 追記箇所

class TopView(TemplateView):
    template_name = 'top.html'

class RegistrationView(CreateView):
    template_name = 'registration.html'
    form_class = RegistrationForm

class MyLoginView(FormView):
    template_name = 'login.html' # 以下追記箇所
    form_class = LoginForm

    def post(self, request, *args, **kwargs):
        email = request.POST['email']
        password = request.POST['password']
        user = authenticate(email=email, password=password)
        if user is not None and user.is_active:
            login(request, user)
        return redirect('account:top')

class MyLogoutView(View):
    
    def get(self, request, *args, **kwargs):
        logout(request)
        return redirect('account:login')

“account/views.py"に"login.html"を記述したので,"templates"フォルダに"login.html"を以下のように作成する.

“templates/login.html"を以下のように編集する.

{% extends 'base.html' %}
{% block content %}
<form method="POST">
  {% csrf_token %}
  {{ form.as_p }}
  <input type="submit" value="Login">
</form>
{% endblock %}

上記を保存し,ブラウザのURLに"http://127.0.0.1:8000/account/top"と入力すると,以下トップページに遷移する."Login"をクリックする.

以下ログインページに遷移する.

上記の項目2で登録したメールアドレスとパスワードを入力し,"Login"ボタンをクリックする.

以下画面に遷移し,上部は"Top"と"Logout"のみ表記される."Logout"をクリックする.

以下のようにログインページに遷移する.

“account/views.py"に追記し,以下のように編集する.

from django.shortcuts import render, redirect
from django.views.generic.edit import CreateView, FormView
from django.views.generic.base import TemplateView, View
from .forms import RegistrationForm, LoginForm
from django.contrib.auth import authenticate, login, logout

class TopView(TemplateView):
    template_name = 'top.html'

class RegistrationView(CreateView):
    template_name = 'registration.html'
    form_class = RegistrationForm

class MyLoginView(FormView):
    template_name = 'login.html'
    form_class = LoginForm

    def post(self, request, *args, **kwargs):
        email = request.POST['email']
        password = request.POST['password']
        user = authenticate(email=email, password=password)
        if user is not None and user.is_active:
            login(request, user)
        return redirect('account:top')

class MyLogoutView(View):
    
    def get(self, request, *args, **kwargs):
        logout(request)
        return redirect('account:login')

class MyUserView(TemplateView): # 以下追記箇所
    template_name = 'user.html'

“account/views.py"で"user.html"を記載したので,"templates"フォルダに"user.html"を以下のように作成する.

“templates/user.html"を以下のように編集する.

{% extends 'base.html' %}
{% block content %}
<h2><p>&nbsp;Hello World!</p></h2>
<h2><p>&nbsp;This is User Page!</p></h2>
{% endblock %}

“account/urls.py"に追記し,以下のように編集する.

from django.urls import path
from .views import ( # 変更箇所
    TopView, RegistrationView,
    MyLoginView, MyLogoutView,
    MyUserView,
)

app_name = 'account'
urlpatterns = [
    path('top/', TopView.as_view(), name='top'),
    path('registration/', RegistrationView.as_view(), name='registration'),
    path('login/', MyLoginView.as_view(), name='login'),
    path('logout/', MyLogoutView.as_view(), name='logout'),
    path('user/', MyUserView.as_view(), name='user'), # 追記箇所
]

“templates/base.html"に追記し,以下のように編集する.

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
  </head>
  <body>
    <nav class="navbar-expand-lg navbar-light bg-light">
      <a class="navbar-brand" href="{% url 'account:top' %}">&nbsp;Top</a>
      {% if user.is_authenticated %}
      <a class="navbar-brand" href="{% url 'account:logout' %}">Logout</a>
      {% else %}
      <a class="navbar-brand" href="{% url 'account:login' %}">Login</a>
      <a class="navbar-brand" href="{% url 'account:registration' %}">Registration</a>
      {% endif %}
      <a class="navbar-brand" href="{% url 'account:user' %}">User Page</a> # 追記箇所
    </nav>
    {% block content %}{% endblock %}
  </body>
</html>

VS Codeのターミナルで,”conda activate 仮想環境名”を実行し,"views_login"のディレクトリにて,以下のように”python manage.py runserver”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewtest\class_based_view
>python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced). # 以下出力箇所
August 25, 2021 - 13:41:40
Django version 3.2.3, using settings 'class_based_view.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

上記の"http://127.0.0.1:8000/"をクリックすると,ブラウザが開くので,ブラウザのURLに"http://127.0.0.1:8000/account/top"を入力すると以下のようにトップページに遷移する.トップページに"Use Page"が赤枠のように追記された.

上記の"Use Page"をクリックすると,以下のように"User Page"に遷移した.

“account/views.py"に追記し,以下のように編集する.

from django.shortcuts import render, redirect
from django.views.generic.edit import CreateView, FormView
from django.views.generic.base import TemplateView, View
from .forms import RegistrationForm, LoginForm
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required # 追記箇所(6~8行目)
from django.utils.decorators import method_decorator
from django.contrib.auth.mixins import LoginRequiredMixin

class TopView(TemplateView):
    template_name = 'top.html'

class RegistrationView(CreateView):
    template_name = 'registration.html'
    form_class = RegistrationForm

class MyLoginView(FormView):
    template_name = 'login.html'
    form_class = LoginForm

    def post(self, request, *args, **kwargs):
        email = request.POST['email']
        password = request.POST['password']
        user = authenticate(email=email, password=password)
        if user is not None and user.is_active:
            login(request, user)
        return redirect('account:top')

class MyLogoutView(View):
    
    def get(self, request, *args, **kwargs):
        logout(request)
        return redirect('account:login')

class MyUserView(TemplateView):
    template_name = 'user.html'

    @method_decorator(login_required) # 以下追記箇所
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

“views_login/settings.py"の最下部に追記し,以下のように編集する.

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

LOGIN_URL = '/account/login' # 追記箇所

上記を保存し,ブラウザから"http://127.0.0.1:8000/account/top"に以下のように遷移する.

上記の"User Page"をクリックすると,以下のようにログインページに遷移した."User Page"は,ログインをしていなければ遷移させることができないようにした.そのため,リダイレクトでログインページに遷移した.

“User Page"でリダイレクトし,ログインページに遷移する場合と直接ログインページに遷移する場合,URLには以下のような差がある.

直接ログインページに遷移:http://127.0.0.1:8000/account/login/
“User Page"からログインページに遷移:http://127.0.0.1:8000/account/login/?next=/account/user/

この差を利用し,"User Page"でリダイレクトし,ログインページに遷移する場合,ログイン後に"User Page"に遷移するようにコードを記述していく.

“account/views.py"に追記し,以下のように編集する.

from django.shortcuts import render, redirect
from django.views.generic.edit import CreateView, FormView
from django.views.generic.base import TemplateView, View
from .forms import RegistrationForm, LoginForm
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib.auth.mixins import LoginRequiredMixin

class TopView(TemplateView):
    template_name = 'top.html'

class RegistrationView(CreateView):
    template_name = 'registration.html'
    form_class = RegistrationForm

class MyLoginView(FormView):
    template_name = 'login.html'
    form_class = LoginForm

    def post(self, request, *args, **kwargs):
        email = request.POST['email']
        password = request.POST['password']
        user = authenticate(email=email, password=password)
        next_url = request.POST['next'] # 追記箇所
        if user is not None and user.is_active:
            login(request, user)
        if next_url: # 追記箇所(28~29行目)
            return redirect(next_url)
        return redirect('account:top')

class MyLogoutView(View):
    
    def get(self, request, *args, **kwargs):
        logout(request)
        return redirect('account:login')

class MyUserView(TemplateView):
    template_name = 'user.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

“templates/login.html"に追記し,以下のように編集する.

{% extends 'base.html' %}
{% block content %}
<form method="POST">
  {% csrf_token %}
  {{ form.as_p }}
  <input type="hidden" name="next" value="{{ request.GET.next }}"> # 追記箇所
  <input type="submit" value="Login">
</form>
{% endblock %}

上記を保存し,ブラウザから"http://127.0.0.1:8000/account/top"に以下のように遷移する.

上記の"User Page"をクリックすると,以下のようにログインページに遷移した.

以下のように上記で登録したユーザー情報を用いてログインを行う.

ログイン後,以下のように"User Page"に遷移した.

なお,Top Pageから"Login"をクリックし,以下のようにログインする.

ログイン後,以下のように"Top Page"に遷移した.

  1. ログイン・ログアウト処理2

項目3にてログイン・ログアウトの実装をしたが,項目4では異なるコードでログイン・ログアウトの実装を行う.

“account/views.py"を以下のように編集する.

from django.shortcuts import render, redirect
from django.views.generic.edit import CreateView, FormView
from django.views.generic.base import TemplateView, View
from .forms import RegistrationForm, LoginForm
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView, LogoutView # 追記箇所

class TopView(TemplateView):
    template_name = 'top.html'

class RegistrationView(CreateView):
    template_name = 'registration.html'
    form_class = RegistrationForm

class MyLoginView(LoginView): # 追記箇所(18~20行目)
    template_name = 'login.html'
    authentication_form = LoginForm

class MyLogoutView(View):
    
    def get(self, request, *args, **kwargs):
        logout(request)
        return redirect('account:login')

class MyUserView(TemplateView):
    template_name = 'user.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

“account/forms.py"を以下のように編集する.

from django import forms
from .models import MyUser
from django.contrib.auth.password_validation import validate_password
from django.contrib.auth.forms import AuthenticationForm # 追記箇所

class RegistrationForm(forms.ModelForm):
    username = forms.CharField(label='name')
    date_of_birth = forms.DateField(label='date_of_birth')
    email = forms.EmailField(label='email address')
    password = forms.CharField(label='password', widget=forms.PasswordInput())

    class Meta:
        model = MyUser
        fields = ['username', 'date_of_birth', 'email', 'password']

    def save(self, commit=False):
        user = super().save(commit=False)
        validate_password(self.cleaned_data['password'], user)
        user.set_password(self.cleaned_data['password'])
        user.save()
        return user

class LoginForm(AuthenticationForm): # 以下追記箇所
    username = forms.EmailField(label='Email Address')
    password = forms.CharField(label='Password', widget=forms.PasswordInput())

“views_login/settings.py"に追記し,以下のように編集する.

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

LOGIN_URL = '/account/login'
LOGIN_REDIRECT_URL = '/account/top' # 追記箇所

VS Codeのターミナルで,”conda activate 仮想環境名”を実行し,"views_login"のディレクトリにて,以下のように”python manage.py runserver”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewtest\class_based_view
>python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced). # 以下出力箇所
August 25, 2021 - 16:03:19
Django version 3.2.3, using settings 'class_based_view.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

上記の"http://127.0.0.1:8000/"をクリックすると,ブラウザが開くので,ブラウザのURLに"http://127.0.0.1:8000/account/top"を入力すると以下のようにトップページに遷移する.

ログイン画面に移動し,以下のように登録した情報を記入し,"Login"ボタンをクリックする.

以下のようにログインに成功し,"Top Page"に遷移した.

“account/views.py"を以下のように編集する.

from django.shortcuts import render, redirect
from django.views.generic.edit import CreateView, FormView
from django.views.generic.base import TemplateView, View
from .forms import RegistrationForm, LoginForm
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView, LogoutView

class TopView(TemplateView):
    template_name = 'top.html'

class RegistrationView(CreateView):
    template_name = 'registration.html'
    form_class = RegistrationForm

class MyLoginView(LoginView):
    template_name = 'login.html'
    authentication_form = LoginForm

class MyLogoutView(LogoutView): # 追記箇所
    pass # 追記箇所

class MyUserView(TemplateView):
    template_name = 'user.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

“views_login/settings.py"に追記し,以下のように編集する.

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

LOGIN_URL = '/account/login'
LOGIN_REDIRECT_URL = '/account/top'
LOGOUT_REDIRECT_URL = '/account/login' # 追記箇所

上記の"http://127.0.0.1:8000/"をクリックすると,ブラウザが開くので,ブラウザのURLに"http://127.0.0.1:8000/account/top"を入力すると以下のようにトップページに遷移する."Login"をクリックする.

以下画面に遷移するので,登録情報を記入し,"Login"ボタンをクリックする.

ログインに成功し,以下のようにTop Pageに遷移する."Logout"をクリックする.

ログイン後,以下のようにログインページに遷移する.

  1. ログインの保持

“views_login/settings.py"に追記し,以下のように編集する.ログインの保持を10秒にすることを意味している.

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

LOGIN_URL = '/account/login'
LOGIN_REDIRECT_URL = '/account/top'
LOGOUT_REDIRECT_URL = '/account/login'

SESSION_COOKIE_AGE = 10 # 追記箇所

上記を保存し,ブラウザから"http://127.0.0.1:8000/account/top"に以下のように遷移する.

ログインをすることによって,"Top Page"に遷移する.

10秒後に更新すると,以下のように自動的にログアウト状態になる.

“account/forms.py"に追記し,以下のように編集する.

from django import forms
from .models import MyUser
from django.contrib.auth.password_validation import validate_password
from django.contrib.auth.forms import AuthenticationForm

class RegistrationForm(forms.ModelForm):
    username = forms.CharField(label='name')
    date_of_birth = forms.DateField(label='date_of_birth')
    email = forms.EmailField(label='email address')
    password = forms.CharField(label='password', widget=forms.PasswordInput())

    class Meta:
        model = MyUser
        fields = ['username', 'date_of_birth', 'email', 'password']

    def save(self, commit=False):
        user = super().save(commit=False)
        validate_password(self.cleaned_data['password'], user)
        user.set_password(self.cleaned_data['password'])
        user.save()
        return user

class LoginForm(AuthenticationForm):
    username = forms.EmailField(label='Email Address')
    password = forms.CharField(label='Password', widget=forms.PasswordInput())
    remember = forms.BooleanField(label='keep login', required=False) # 以下追記箇所

“account/views.py"に追記し,以下のように編集する.

from django.shortcuts import render, redirect
from django.views.generic.edit import CreateView, FormView
from django.views.generic.base import TemplateView, View
from .forms import RegistrationForm, LoginForm
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView, LogoutView

class TopView(TemplateView):
    template_name = 'top.html'

class RegistrationView(CreateView):
    template_name = 'registration.html'
    form_class = RegistrationForm

class MyLoginView(LoginView):
    template_name = 'login.html'
    authentication_form = LoginForm

    def form_valid(self, form): # 追記箇所(以下5行が追記箇所)
        remember = form.cleaned_data['remember']
        if remember:
            self.request.session.set_expiry(1000000)
        return super().form_valid(form)

class MyLogoutView(LogoutView):
    pass

class MyUserView(TemplateView):
    template_name = 'user.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

上記を保存し,ブラウザから"http://127.0.0.1:8000/account/top"に以下のように遷移する."Login"をクリックする.

以下のようにログインページに遷移する.赤枠の"keep login"が加わった.チェックをするとログイン状態をキープすることができる.チェックをしないと10秒でログアウト状態になる.

以下のようにユーザー情報を記述し,"keep login"にチェックを入れ,"Login"ボタンをクリックする.

以下のようにログイン状態になり,Top Pageに遷移した.

10秒後,更新をしてもログアウトにならない.

  1. 反省点

本記事にてアプリ名を"account"と名付けたが,「OAuth認証を用いたgoogleでのログイン方法」で当該アプリ名はエラーを引き起こした.そのため,当該アプリ名は付与せず,"myaccount"などを利用するほうがよい.

  1. 参照

https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#custom-users-and-proxy-models

https://docs.djangoproject.com/ja/3.1/topics/class-based-views/intro/#decorating-the-class

https://docs.djangoproject.com/en/3.2/topics/auth/default/#the-login-required-decorator

https://docs.djangoproject.com/en/3.2/topics/class-based-views/intro/#decorating-the-class

https://docs.djangoproject.com/en/3.1/topics/auth/default/

https://docs.djangoproject.com/en/3.1/topics/http/sessions/

https://docs.djangoproject.com/en/3.1/ref/settings/#session-cookie-age

https://docs.djangoproject.com/ja/3.1/topics/http/sessions/#django.contrib.sessions.backends.base.SessionBase.set_expiry

以上