1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Djangoカスタムユーザーの作成・登録・ログイン・ログアウト 関数ベース

Posted at

目次

Usersモデル作成
ユーザー登録
ログイン
ログアウト

Usersモデルの作成

「accounts」アプリを作成し、「models.py」にUsersモデルを定義します。
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.contrib.auth.models import UserManagerの二つをインポートします。
UsersモデルにはAbstractBaseUserPermissionsMixinを継承させます。

AbstractBaseUser
ユーザーの認証機能のみが定義されたクラス。
PermissionsMixin
スーパーユーザーの権限などが定義されたクラス
これらを継承することで認証やスーパーユーザーの管理のみを継承し、ユーザークラスに持たせる名前やメールアドレス、ユーザーアイコンなどを作成するアプリに合わせてフィールドを独自に設定することができます。
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.contrib.auth.models import UserManager


class Users(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=255)
    email = models.EmailField(max_length=255, unique=True)
    icon = models.FileField(null=True, upload_to='icon/')
    is_staff = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email' #ユーザーを一意に識別する
    REQUIRED_FIELDS = ['username'] # スーパーユーザーに名前を持たせる

    class Meta:
        db_table = 'users' #テーブル名を指定

USERNAME_FIELD = 'email'とする事で認証にemailを使う事ができる。

デフォルトではDjangoのユーザーモデルが利用されてしまうので、カスタムユーザーを利用するには「settings.py」にAUTH_USER_MODELを定義し、作成したUsersモデルを指定する必要があります。

settings.py
AUTH_USER_MODEL = 'accounts.Users'

AUTH_USER_MODELの設定はマイグレーションを行う前にするようにしましょう。
設定できたらマイグレーションします。

ターミナル
python manage.py makemigrations accounts

python manage.py migrate

ユーザー登録

ユーザー登録用のフォームを作成します。

accountsフォルダーに新しく「forms.py」を作成します。
パスワードのバリデーションを行うためのvalidate_passwordと「models.py」で作成したUsersをインポートします。

forms.py
from django import forms
from django.contrib.auth.password_validation import validate_password
from .models import Users


class SignInForm(forms.ModelForm):
    username = forms.CharField(label="名前")
    email = forms.EmailField(label='メールアドレス')
    password = forms.CharField(label='パスワード', widget=forms.PasswordInput)
    confirm_password = forms.CharField(label='パスワード再入力', widget=forms.PasswordInput)

    class Meta:
        model = Users
        fields = ('username', 'email', 'password')
    
    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        confirm_password = cleaned_data.get('confirm_password')
        if password != confirm_password:
            raise forms.ValidationError('パスワードが一致しません。')
    
    def save(self):
        user = super().save(commit=False)
        validate_password(self.cleaned_data.get('password'), user)
        user.set_password(self.cleaned_data.get('password'))
        user.save()
        return user

forms.ModelFormを継承する事でフォームの内容をsave()メソッドでデータベースに登録する事ができる。
passwordconfirm_passwordwidget=forms.PasswordInputを指定する事でパスワード入力用のフォームにする事ができる。また、comfirm_passwordによりパスワードをもう一度入力してもらう事で、パスワードの入力ミスを予防するようにしています。

class Meta

class Metamodel=Usersでフォーム内容を登録するモデルを指定し、fieldsで登録するフィールドを指定する。(confirm_passwordはデータベースには登録しないため省く)

cleanメソッド

clean()メソッドはpasswordconfirm_passwordが一致するか判定し、一致しない場合はバリデーションエラーを返す。
cleaned_data = super().clean()でフォームに入力された値を取り出しcleaned_dataに格納。(super()は親クラスを指し、この場合はSignInFormを指している)

ターミナル
# super().clean()により取得した値
{'username': 'test', 'email': 'test@example.com', 'password': 'noteapppass', 'confirm_password': 'noteapppass'}

passwordとconfirm_passwordをcleaned_data.get('フィールド名')としてそれぞれ取り出す。

saveメソッド

save()メソッドはデフォルトのsaveメソッドでは上記のようにパスワードが平文のままになってしまうので、saveメソッドをオーバーライドしてパスワードを暗号化して保存するようにします。
user = super().save(commit=False)とすることでフォームの値を取得する。(commit=Falseでデータベースに保存せず値だけ取り出す事が可能)
validate_passwordによりパスワードのバリデーションを行う。
user.set_passwordメソッドでパスワードの暗号化を行い、user().save()でデータベースに保存する。

ユーザー登録のビューを作成

「accounts」フォルダの「views.py」にユーザー登録の処理を書きます。
from django.shortcuts import render, redirect ⬅︎ redirectを追加
from django.core.exceptions import ValidationError
from . import forms
renderの後にredirectを追加と例外処理用のValidationError最後にformをインポートします。

views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.core.exceptions import ValidationError
from . import forms


def signin(request):
    signin_form = forms.SignInForm(request.POST or None)
    if signin_form.is_valid():
        try:
            signin_form.save()
            return redirect('accounts:home')
        except ValidationError as e:
            signin_form.add_error('password', e)
    return render(request,'accounts/signin.html', context={
        'signin_form': signin_form,
    })

forms.SignInForm(request.POST or None)でPOSTメソッドで送られてきたデータをrequest.POSTで受け取り、GETメソッドの場合はNoneを返します。
signin_form.is_valid()でバリデーションのチェックとformで定義したcleanメソッドも実行されます。

tryにより例外処理を行い、signin_form.save()でformで定義したsaveメソッドを実行します。この時、SignInFormで定義したsaveメソッドのvalidate_passwordでバリデーションに引っかかった場合は、exceptが呼ばれsignin_form.add_error('password', e)でフォームのpasswordフィールドにエラーが渡されます。

例外なく実装された場合はredirectで遷移させます。

ログイン

ログイン用のフォームを作成

「accounts」の「forms.py」にログイン用のフォームを追加します。

forms.py
class LoginForm(forms.Form):
    email = forms.EmailField(label="メールアドレス")
    password = forms.CharField(label="パスワード", widget=forms.PasswordInput)

ログインフォームではデータベースに保存することはないのでforms.Formを継承します。
今回はログインにメールアドレスを使うので、メールアドレスとパスワードのフィールドを定義します。

ログイン用のビューを作成

from django.contrib.auth import authenticate, login
from django.contrib import messagesをインポートします。
authenticateはユーザーの認証を行い、loginでログインの処理を行います。
messagesはログイン後やログインに失敗した場合にメッセージを表示するために使います。

views.py
from django.contrib.auth import authenticate, login


def user_login(request):
    login_form = forms.LoginForm(request.POST or None)
    if login_form.is_valid():
        email = login_form.cleaned_data.get('email')
        password = login_form.cleaned_data.get('password')
        user = authenticate(email=email, password=password)
        if user:
            login(request, user)
            messages.success(request, 'ログインしました。')
            return redirect('accounts:home')
        else:
            message.warning(request, 'メールアドレスかパスワードが間違っています。')
        return render(request, 'accounts/login.html', context={
            'login_form': login_form,
        })

user = authenticate(email=email, password=password)でメールアドレスとパスワードが一致したユーザーを取得する。
userを取得できた場合はlogin(request, user)でユーザーのログイン処理を行う。
messages.success(request, 'ログインしました。')によりmessagesのsuccessタグでメッセージを渡す。タグをつけることでテンプレート側での表示に使う事ができる。
例:

index.html
<div class="message">
    {% if messages %}
        {% for message in messages %}
            <div class="alert alert-{{ message.tags }}">
                {{ message.message }}
            </div>
        {% endfor %}
    {% endif %}
</div>

テンプレート側でmessagesをfor文で取得し{{ message.message }}でメッセージの内容を表示する。
Bootstrapを使用する場合はclass="alert alert-{{ message.tags }}"でタグを取得し(messages.successの場合successを取得できる)アラートの色をタグの種類により変える事ができる。
スクリーンショット 2023-02-13 13.22.35.png
スクリーンショット 2023-02-13 13.28.42.png

ログアウト

ログアウト用のビューを作成

from django.contrib.auth import authenticate, login, logout ⬅︎ logoutを追加
from django.contrib.auth.decorators import login_required
login_requiredはユーザーがログインしているかを判定してくれます。ログアウト関数のデコレータとしてログインしていない場合は関数を実行されないようにします。

views.py
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required


@login_required
def user_logout(request):
    logout(request)
    messages.success(request, 'ログアウトしました。')
    return redirect('accounts:home')

logout(request)によりログアウトの処理を行ます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?