環境
Windows 11 Home
Python 3.10.2
Django 4.0.2
venv利用あり
背景
Djangoにおいてユーザモデルはカスタムユーザモデルを作成するのがセオリーらしいので記事にした。
本ページでは触れないが、後々、初回ログイン時にパスワードを強制変更させるためのカラムを用意しておく。
関連記事
Django 第1回:Django Custom User Model の作成 今回
Django 第2回:Django 初回ログイン時にパスワード変更を強制する
Django 第3回:Django 一定期間パスワードを変更していないユーザにパスワード変更を強制する
Django 第4回:Django ランダムかつ有効期限のあるURLを生成し、上位者に承認してもらいアカウントを発行する
Django 第5回:Django パスワード試行回数ロックとランダムかつ有効期限付きURLでの本人確認による解除
状態
python startproject mysite
でプロジェクトを構築したばかりの状態。
カスタムユーザモデルを作成し、EmailとPasswordの認証に変更する。
手順:mysite/settings.py
以下コマンドでusers
Appを作成する。
python manage.py startapp users
続いてsettings.py
に先ほど作成したusers
を認識させるのとAUTH_USER_MODEL
を定義する。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Local
'users', #追加
]
AUTH_USER_MODEL = 'users.User' # 追加
...
LANGUAGE_CODE = 'ja' # 変更
TIME_ZONE = 'Asia/Tokyo' # 変更
##手順:user/models.py
from django.utils import timezone
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, UserManager
from django.core.mail import send_mail
import uuid as uuid_lib
class UserManager(UserManager):
def _create_user(self, email, password, **extra_fields):
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
if extra_fields.get("is_staff") is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get("is_superuser") is not True:
raise ValueError('Superuser must have is_superuser=True.')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.username = email
user.set_password(password)
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
"""Custom User"""
class Meta:
verbose_name = 'ユーザ'
verbose_name_plural = 'ユーザ'
uuid = models.UUIDField(default=uuid_lib.uuid4, primary_key=True, editable=False) # 管理ID
username = models.CharField(max_length=30, unique=False) # ユーザ氏名
email = models.EmailField(unique=True, blank=True, null=True) # メールアドレス = これで認証する
is_active = models.BooleanField(default=True) # アクティブ権限
is_staff = models.BooleanField(default=True) # スタッフ権限
is_superuser = models.BooleanField(default=False) # 管理者権限
date_joined = models.DateTimeField(default=timezone.now) # アカウント作成日時
password_changed = models.BooleanField(default=False) # パスワードを変更したかどうかのフラグ
password_changed_date = models.DateTimeField(blank=True, null=True) # 最終パスワード変更日時
objects = UserManager()
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'email'
REQUIRED_FIELD = ''
def clean(self):
super().clean()
self.email = self.__class__.objects.normalize_email(self.email)
def email_user(self, subject, message, from_email=None, **kwargs):
send_mail(subject, message, from_email, [self.email], **kwargs)
def __str__(self):
return self.email
def get_full_name(self):
return self.username
def get_short_name(self):
return self.username
verbose_name
は管理画面でUsers
ではなく日本語で表示させるためのもの。
email = models.EmailField(unique=True, blank=True, null=True)
の中でblank=True, null=True
がないと、管理画面で
ユーザを追加する際にIntegrityError: UNIQUE constraint failed: users_user.email
のエラーが出るので注意。
:user/admin.py
models.pyだけでは変更が確認できないので、管理画面にカスタムユーザを表示させる。
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext, gettext_lazy as _
from .models import User
@admin.register(User)
class UserAdmin(UserAdmin):
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal Info',), {'fields': ('email',)}),
(_('Permissions',), {'fields': ('is_active', 'is_staff', 'is_superuser',)}),
(_('Password',), {'fields': ('password_changed', 'password_changed_date',)}),
(_('Important Dates',), {'fields': ('last_login', 'date_joined',)}),
)
list_display = ('username', 'email', 'is_active',)
##手順:migrationとrunserver
Visual Studio Code insiders(以降、VSCode)からターミナルを開き、
python manage.py makemigrations
でmakemigrationファイルを作成
python manage.py migrate
でmigrateを実行
python manage.py createsuperuser
で管理者権限のアカウントを作る
admin@admin.com
と入力したが好きなメールアドレスを入力してOK
パスワードは2回入力するが、画面には表示されない
パスワードを簡単なものにしたため警告が出たが無視してかまわない。あとで変更できる。
実行。
python manage.py runserver
http://127.0.0.1:8000/
にアクセスするとロケットが飛んでいる。サーバ立ち上げ成功の印。
http://127.0.0.1:8000/admin
で管理画面に遷移する。
先ほどのEmailとPasswordを入力してログインする。
ユーザを押下
先ほどのアカウントが表示されている。
フィルタや検索ボックスがあるが、カスタマイズ可能。別の記事で紹介したい。
先ほどのアカウントをクリック
詳細が表示される。
python:users\admin.py
で設定しているが詳細は別の記事で紹介したい。
お疲れさまでした。
参考
Django 第1回:Django Custom User Model の作成
Django 第2回:Django 初回ログイン時にパスワード変更を強制する
Django 第3回:Django 一定期間パスワードを変更していないユーザにパスワード変更を強制する
Django 第4回:Django ランダムかつ有効期限のあるURLを生成し、上位者に承認してもらいアカウントを発行する
Django 第5回:Django パスワード試行回数ロックとランダムかつ有効期限付きURLでの本人確認による解除