- カスタムユーザーモデルの概念がどうしても理解できない
- 標準のUserモデルからカスタムユーザーモデルへの変更方法が知りたい
Djangoには標準でログインなどの認証に使えるUser
モデルが定義されています。
ところが、残念ながら標準のUser
モデルはカスタマイズがほとんどできません。
そのため標準のUserモデルにあるフィールドやメソッドでは足りない場合には、独自にユーザーモデルを作る必要があります。
これをカスタムユーザーモデルと言います。
このカスタムユーザーモデルは設定方法がだいぶ煩雑になっているので、本記事で詳しく解説します。
【Django】ユーザーモデルの全体像
概略を知っておいた方が理解が進むと思うので、まずはDjangoのユーザーモデルの全体像をご説明します。
Djangoのユーザーモデルを図式化すると以下ようになります。
一番右にあるUserが、Djangoで標準で用意されているUserモデルです。
そのため、カスタムユーザーを定義するには次の二つのいずれかになります。
- AbstractUserを継承する
- AbstractBaseUserとPermissionsMixinを継承する
Django標準のUserモデルと同じものが欲しければAbstractUserだけを継承します。
一方でAbstractUserモデルで定義されているフィールドが不要なら、AbstractBaseUserとPermissionsMixinを継承する流れになります。
AbstractBaseUserの構造
ユーザー認証に必要な基本的なフィールドを提供しています。
- password
- last_login
PermissionsMixinの構造
ユーザーに権限を付与するためのフィールドが含まれます。
- is_superuser
- groups
- user_permissions
AbstractUserの構造
DjangoデフォルトのUserモデルフィールドが定義されています。
- username
- First_name
- last_name
- is_staff
- is_active
- date_joined
AbstractUserはAbstractBaseUserとPermissionsMixinを継承しています。
そのため、親クラスが持つ以下のようなフィールドも持っています。
- password
- last_login
- is_superuser
- groups
- user_permissions
【具体的手順】カスタムユーザーモデルの作り方
カスタムユーザーモデルを作成するには、次のステップが必要です。
- ユーザー管理用のアプリを作成
- モデルを定義
- 認証に使うユーザーモデルを変更
- 管理画面への適用
- モデルのマイグレーション
カスタムユーザー用のアプリを作成
カスタムユーザーモデルを格納するアプリを作成します。
# userアプリの作成
mkdir apps/user
python manage.py startapp user apps/user
settings.pyのINSTALLED_APPSにアプリを登録しておきましょう。
INSTALLED_APPS = [
# 中略
"apps.user.apps.UserConfig",
]
カスタムユーザーモデルの作成
カスタムユーザーモデルを定義したmodels.pyは、最終的に以下のような形になります。
【結論】models.py
from django.contrib.auth.models import (
AbstractBaseUser,
BaseUserManager,
PermissionsMixin,
)
from django.db import models
from django.utils import timezone
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("The Email field must be set")
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_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
return self.create_user(email, password, **extra_fields)
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
objects = CustomUserManager()
USERNAME_FIELD = "email"
少し長いので、一つずつ確認していきましょう。
CustomUserクラス
順番は前後しますが、先にCustomUserモデルから説明します。
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = "email"
上記のようにUSERNAME_FIELD
としてemail
を指定すると、メールアドレスとパスワードを使って認証します。
USERNAME_FIELD
で指定されるフィールドは認証に使われるので、必ずunique=Trueとして一意性を確保しておきましょう。
CustomUserManagerクラス
CustomUserモデルを修正するため、BaseUserManagerを継承したマネージャークラスを作成します。
おさらいですが、CustomUserManagerは以下のように設定しました。
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
# emailがない場合はエラー
if not email:
raise ValueError("The Email field must be set")
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_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
return self.create_user(email, password, **extra_fields)
ここでcreate_superuser()メソッドがないと、createsuperuserコマンドでスーパーユーザーを作っても、管理画面にログインすることができないのです。
理由をより詳しく説明すると、以下になります。
- 管理画面にログインできるユーザーの条件
is_staff
:True
is_superuser
:True
- カスタムユーザーでcreatesuperuserすると一般ユーザーが作成されてしまう
is_staff
とis_superuser
のデフォルトはFalse
そこで、createsuperuserをした時に限ってis_staff
, is_superuser
をTrue
にするよう、次のコードを追加しています。
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
return self.create_user(email, password, **extra_fields)
これでcreatesuperuserしたユーザーに限ってはis_staff
, is_superuser
がTrue
となり、無事に管理画面にログインできるようになります。
続いてcreate_user()
メソッドです。
このメソッドはユーザーの新規追加で呼びだされます。
def create_user(self, email, password=None, **extra_fields):
# emailがない場合はエラー
if not email:
raise ValueError("The Email field must be set")
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
引数で受け取っている**extra_fields
は、email
, password
以外のフィールドが辞書で格納されます。
self.normalize_email()
はemailを正規化するメソッドです。正規化とは、例えば@マーク以下のドメイン部分を小文字にするなどですね。
user.set_password()
はパスワードをハッシュ化して保存するメソッドです。
最後にuser.save(using=self._db)
はデータベースへの保存を表します。self._db
はsettings.pyでDATABASESとして定義されたデータベースが指定できます。
カスタムユーザーモデルを認証で使うモデルに指定
settings.pyに以下のコードを追記します。
settings.pyに追記
AUTH_USER_MODEL = "user.CustomUser"
上記でDjango標準のUser
モデルではなくCustomUser
モデルが認証に使われるようになります。
管理画面にカスタムユーザーモデルを反映
カスタムユーザーモデルを管理画面に表示するため、user/admin.pyに以下のコードを記載します。
【結論】admin.py
from django.contrib import admin
from .models import CustomUser
class CustomUserAdmin(admin.ModelAdmin):
# 一覧画面: 表示項目
list_display = (
"email",
"last_name",
"first_name",
"is_staff",
"is_active",
"date_joined",
)
# 一覧画面: サイドバーフィルター
list_filter = (
"email",
"is_staff",
"is_active",
)
# 一覧画面: 検索ボックス
search_fields = ("email",)
# 一覧画面: ソート(降順ならフィールド名の先頭に-)
ordering = ("email",)
# 詳細画面: 表示項目
basic = ("username", "email", "password")
personal = ("last_name", "first_name", "date_joined")
auth = ("is_staff", "is_active")
fieldsets = (
("BasicInfo", {"fields": basic}),
("Personal", {"fields": personal}),
("Auth", {"fields": auth}),
)
admin.site.register(CustomUser, CustomUserAdmin)
モデルのマイグレーション
最後にマイグレーションを行ってください。
python manage.py makemigrations
python manage.py migrate
以上でカスタムユーザーモデルがDjangoプロジェクトに反映されているはずです。
まとめ
カスタムユーザーモデルを作成するまでの流れは次のとおりでした。
- ユーザー管理用のアプリを作成
- モデルを定義
- 認証に使うユーザーモデルを変更
- 管理画面への適用
- モデルのマイグレーション
Userモデルだけを触っているとDjangoの内部構造まで目が行くことがないので、今回の記事は難易度が高い内容だったかもしれません。
ぜひ個人開発などの際に参考にしてみてください。
コメント