【Django3 入門】クラスベースビューにおけるログイン処理

Django

今回は、クラスベースビューにおけるログイン、ログアウト処理や、
リダイレクト処理、セッション時間の変更などみていきます。

前提

・「my_app」というアプリを作成、「settings.py」に登録
・「manage.py」と同じ階層に「templates」「static」ディレクトリを作成し、読込先のディレクトリのパスをこちらに変更

.
.
.
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')
STATIC_DIR = os.path.join(BASE_DIR, 'static').
.
.
.
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [TEMPLATE_DIR,],
.
.
.
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    STATIC_DIR,
)


・プロジェクトディレクトリの「urls.py」に以下のようにパスを登録

path('my_app/', include('my_app.urls')),

ユーザー登録、ログイン、ログアウト

モデルの作成

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

# Create your models here.

class UserManager(BaseUserManager):
    def create_user(self, username, email, password=None):
        if not email:
            raise ValueError('メールアドレスを入力してください')
        user = self.model(
            username=username,
            email=email
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=150)
    email = models.EmailField(max_length=255, unique=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    objects = UserManager()

    def get_absolute_url(self):
        return reverse_lazy('my_app:home')


「settings.py」の修正

.
.
.
AUTH_USER_MODEL = 'my_app.User'


マイグレーションの実行

python manage.py makemigrations my_app
python manage.py migrate


「forms.py」の作成

from django import forms
from django.db import models
from django.forms import fields
from .models import User
from django.contrib.auth.password_validation import validate_password

class RegistForm(forms.ModelForm):
    username = forms.CharField(label='名前')
    age = forms.IntegerField(label='年齢', min_value=0)
    email = forms.EmailField(label='メールアドレス')
    password = forms.CharField(label='パスワード', widget=forms.PasswordInput())

    class Meta:
        model = User
        fields = ['username', 'age', '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 UserLoginForm(forms.Form):
    email = forms.EmailField(label='メールアドレス')
    password = forms.CharField(label='パスワード', widget=forms.PasswordInput())
from django import forms
from django.db import models
from django.forms import fields
from .models import User
from django.contrib.auth.password_validation import validate_password

class RegistForm(forms.ModelForm):
    username = forms.CharField(label='名前')
    age = forms.IntegerField(label='年齢', min_value=0)
    email = forms.EmailField(label='メールアドレス')
    password = forms.CharField(label='パスワード', widget=forms.PasswordInput())

    class Meta:
        model = User
        fields = ['username', 'age', '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 UserLoginForm(forms.Form):
    email = forms.EmailField(label='メールアドレス')
    password = forms.CharField(label='パスワード', widget=forms.PasswordInput())


「views.py」の修正

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

# Create your views here.

class HomeView(TemplateView):
    template_name = 'home.html'

class RegistUserView(CreateView):
    template_name = 'regist.html'
    form_class = RegistForm

class UserLoginView(FormView):
    template_name = 'user_login.html'
    form_class = UserLoginForm

    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('my_app:home')

class UserLogoutView(View):
    def get(self, request, *args, **kwargs):
        logout(request)
        return redirect('my_app:user_login')


「urls.py」の修正

from django.urls import path
from .views import (
    RegistUserView, HomeView, UserLoginView, UserLogoutView
)

app_name = 'my_app'

urlpatterns = [
    path('home', HomeView.as_view(), name='home'),
    path('regist', RegistUserView.as_view(), name='regist'),
    path('user_login', UserLoginView.as_view(), name='user_login'),
    path('user_logout', UserLogoutView.as_view(), name='user_logout'),
]


HTMLファイルの作成

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
</head>
<body>
    <nav class="navbar navbar-expand navbar-light bg-light">
        <a href="{% url 'my_app:home' %}" class="navbar-brand">ホーム</a>
        {% if user.is_authenticated %}
            <a href="{% url 'my_app:user_logout' %}" class="navbar-brand">ログアウト</a>
        {% else %}
            <a href="{% url 'my_app:user_login' %}" class="navbar-brand">ログイン</a>
            <a href="{% url 'my_app:regist' %}" class="navbar-brand">ユーザー登録</a>
        {% endif %}
    </nav>
    <div class="container py-4">
        {% block content %}{% endblock %}
    </div>
</body>
</html>
{% extends 'base.html' %}
{% block content %}

<h1>ホーム画面</h1>

{% endblock %}
{% extends 'base.html' %}
{% block content %}

<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="ユーザー登録">
</form>

{% endblock %}
{% extends 'base.html' %}
{% block content %}

<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="ログイン">
</form>

{% endblock %}

未ログイン時に別ページへリダイレクト

未ログイン状態で、ログインしていないと見れないページにアクセスしたときに、
別ページへリダイレクトする方法をみていきます。



「views.py」の修正

.
.
.
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
.
.
.
@method_decorator(login_required, name='dispatch')
class UserView(TemplateView):
    template_name = 'user.html'

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


パスの追加

from django.urls import path
from .views import (
    RegistUserView, HomeView, UserLoginView, UserLogoutView, UserView
)

app_name = 'my_app'

urlpatterns = [
    path('home', HomeView.as_view(), name='home'),
    path('regist', RegistUserView.as_view(), name='regist'),
    path('user_login', UserLoginView.as_view(), name='user_login'),
    path('user_logout', UserLogoutView.as_view(), name='user_logout'),
    path('user', UserView.as_view(), name='user'),
]


「base.html」の修正

<nav class="navbar navbar-expand navbar-light bg-light">
.
.
.
    {% endif %}
    <a href="{% url 'my_app:user' %}" class="navbar-brand">ユーザー画面</a>
</nav>


「settings.py」の修正(未ログイン時の遷移先を指定)

.
.
.
LOGIN_URL = '/my_app/user_login'


未ログイン状態


ログイン状態




また、この時点では未ログイン状態で「ユーザー画面」を押してログインすると、ホーム画面に遷移してしまいます。



これを、「ユーザー画面」→「ログイン」→「ユーザー画面」となるよう修正します。




「user_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="ログイン">
</form>

{% endblock %}


「views.py」の修正

.
.
.
class UserLoginView(FormView):
    template_name = 'user_login.html'
    form_class = UserLoginForm

    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:
            return redirect(next_url)
        return redirect('my_app:home')
.
.
.

LoginView, LogoutView

「forms.py」の修正

.
.
.
from django.contrib.auth.forms import AuthenticationForm
.
.
.
# class UserLoginForm(forms.Form):
#     email = forms.EmailField(label='メールアドレス')
#     password = forms.CharField(label='パスワード', widget=forms.PasswordInput())

class UserLoginForm(AuthenticationForm):
    username = forms.EmailField(label='メールアドレス') # ユーザーを一意に指定するもの
    password = forms.CharField(label='パスワード', widget=forms.PasswordInput())


「views.py」の修正

.
.
.
# class UserLoginView(FormView):
#     template_name = 'user_login.html'
#     form_class = UserLoginForm

#     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:
#             return redirect(next_url)
#         return redirect('my_app:home')

class UserLoginView(LoginView):
    template_name = 'user_login.html'
    authentication_form = UserLoginForm


# class UserLogoutView(View):
#     def get(self, request, *args, **kwargs):
#         logout(request)
#         return redirect('my_app:user_login')

class UserLogoutView(LogoutView):
    pass # これのみ
.
.
.


「settings.py」の修正

.
.
.
LOGIN_REDIRECT_URL = '/my_app/home' #ログイン時のリダイレクト先
LOGOUT_REDIRECT_URL = '/my_app/user_login' #ログアウト時のリダイレクト先

セッション

デフォルトのセッション時間を変更

.
.
.
SESSION_COOKIE_AGE = 1 # 1秒


ログインしてから1秒以上経つと、自動的にログアウトされます。



「forms.py」の修正

.
.
.
class UserLoginForm(AuthenticationForm):
    username = forms.EmailField(label='メールアドレス') # ユーザーを一意に指定するもの
    password = forms.CharField(label='パスワード', widget=forms.PasswordInput())
    remember = forms.BooleanField(label='ログイン状態を保持', required=False)


「views.py」の修正

.
.
.
class UserLoginView(LoginView):
    template_name = 'user_login.html'
    authentication_form = UserLoginForm

    def form_valid(self, form):
        remember = form.cleaned_data['remember']
        if remember:
            self.request.session.set_expiry(100000000)
        return super().form_valid(form)
.
.
.





今回は以上になります。
ご覧いただきありがとうございました!

続きはこちら↓

コメント

コンタクトフォーム

    タイトルとURLをコピーしました