目次
Usersモデルの作成
「accounts」アプリを作成し、「models.py」にUsersモデルを定義します。
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.contrib.auth.models import UserManager
の二つをインポートします。
UsersモデルにはAbstractBaseUser
とPermissionsMixin
を継承させます。
- AbstractBaseUser
- ユーザーの認証機能のみが定義されたクラス。
- PermissionsMixin
- スーパーユーザーの権限などが定義されたクラス
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モデルを指定する必要があります。
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
をインポートします。
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()
メソッドでデータベースに登録する事ができる。
password
とconfirm_password
にwidget=forms.PasswordInput
を指定する事でパスワード入力用のフォームにする事ができる。また、comfirm_password
によりパスワードをもう一度入力してもらう事で、パスワードの入力ミスを予防するようにしています。
class Meta
class Meta
のmodel=Users
でフォーム内容を登録するモデルを指定し、fields
で登録するフィールドを指定する。(confirm_passwordはデータベースには登録しないため省く)
cleanメソッド
clean()
メソッドはpassword
とconfirm_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
をインポートします。
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」にログイン用のフォームを追加します。
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
はログイン後やログインに失敗した場合にメッセージを表示するために使います。
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タグでメッセージを渡す。タグをつけることでテンプレート側での表示に使う事ができる。
例:
<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を取得できる)アラートの色をタグの種類により変える事ができる。
ログアウト
ログアウト用のビューを作成
from django.contrib.auth import authenticate, login, logout
⬅︎ logoutを追加
from django.contrib.auth.decorators import login_required
login_required
はユーザーがログインしているかを判定してくれます。ログアウト関数のデコレータとしてログインしていない場合は関数を実行されないようにします。
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)
によりログアウトの処理を行ます。