\ ポイント最大11倍! /

【Django】カスタムユーザーモデルの作り方【認証】

  • カスタムユーザーモデルの概念がどうしても理解できない
  • 標準のUserモデルからカスタムユーザーモデルへの変更方法が知りたい

Djangoには標準でログインなどの認証に使えるUserモデルが定義されています。

ところが、残念ながら標準のUserモデルはカスタマイズがほとんどできません

そのため標準のUserモデルにあるフィールドやメソッドでは足りない場合には、独自にユーザーモデルを作る必要があります。

これをカスタムユーザーモデルと言います。

このカスタムユーザーモデルは設定方法がだいぶ煩雑になっているので、本記事で詳しく解説します。

もちろん、プロジェクトの要件がUserモデルで十分ならあえてカスタムユーザーを作成する必要はありません。

【Django】ユーザーモデルの全体像

概略を知っておいた方が理解が進むと思うので、まずはDjangoのユーザーモデルの全体像をご説明します。

» 設定方法だけ知りたいお急ぎの方はこちら

Djangoのユーザーモデルを図式化すると以下ようになります。

一番右にあるUserが、Djangoで標準で用意されているUserモデルです。

そのため、カスタムユーザーを定義するには次の二つのいずれかになります。

  • AbstractUserを継承する
  • AbstractBaseUserとPermissionsMixinを継承する

Django標準のUserモデルと同じものが欲しければAbstractUserだけを継承します。

一方でAbstractUserモデルで定義されているフィールドが不要なら、AbstractBaseUserとPermissionsMixinを継承する流れになります。

以下はカスタムユーザーモデルを作成する場合に絞って、できるだけシンプルに解説します。

AbstractBaseUserの構造

ユーザー認証に必要な基本的なフィールドを提供しています。

AbstractBaseUserが持つフィールド
  • password
  • last_login

PermissionsMixinの構造

ユーザーに権限を付与するためのフィールドが含まれます。

PermissionsMixinが持つフィールド
  • is_superuser
  • groups
  • user_permissions

AbstractUserの構造

DjangoデフォルトのUserモデルフィールドが定義されています。

AbstractUserが持つフィールド
  • username
  • First_name
  • last_name
  • email
  • is_staff
  • is_active
  • date_joined

AbstractUserはAbstractBaseUserとPermissionsMixinを継承しています。

そのため、親クラスが持つ以下のようなフィールドも持っています。

親クラスから継承したフィールド
  • password
  • last_login
  • is_superuser
  • groups
  • user_permissions

Django標準のUserモデルはAbstractUserとほぼ同じ内容と考えていただいて大丈夫だと思います。

【具体的手順】カスタムユーザーモデルの作り方

カスタムユーザーモデルを作成するには、次のステップが必要です。

  1. ユーザー管理用のアプリを作成
  2. モデルを定義
  3. 認証に使うユーザーモデルを変更
  4. 管理画面への適用
  5. モデルのマイグレーション

できるだけ操作やコードが必要な理由も合わせて、詳しく説明していきます。

カスタムユーザー用のアプリを作成

カスタムユーザーモデルを格納するアプリを作成します。

# userアプリの作成
mkdir apps/user
python manage.py startapp user apps/user

settings.pyのINSTALLED_APPSにアプリを登録しておきましょう。

INSTALLED_APPS = [
    # 中略
    "apps.user.apps.UserConfig",
]

appsディレクトリ配下ではなくmanage.pyと同じディレクトリにアプリを配置する場合には、適宜appsを削除して読み替えてください。

カスタムユーザーモデルの作成

カスタムユーザーモデルを定義した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として一意性を確保しておきましょう。

ちなみにDjangoのデフォルトではusernameで認証されます。

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_staffis_superuserのデフォルトはFalse

そこで、createsuperuserをした時に限ってis_staff, is_superuserTrueにするよう、次のコードを追加しています。

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_superuserTrueとなり、無事に管理画面にログインできるようになります。


続いて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プロジェクトに反映されているはずです。

まとめ

カスタムユーザーモデルを作成するまでの流れは次のとおりでした。

カスタムユーザーモデル作成までの流れ
  1. ユーザー管理用のアプリを作成
  2. モデルを定義
  3. 認証に使うユーザーモデルを変更
  4. 管理画面への適用
  5. モデルのマイグレーション

Userモデルだけを触っているとDjangoの内部構造まで目が行くことがないので、今回の記事は難易度が高い内容だったかもしれません。

ぜひ個人開発などの際に参考にしてみてください。

この記事が気に入ったら
フォローしてね!

シェア・記事の保存はこちら!

この記事を書いた人

karo@プログラマのアバター karo@プログラマ プログラマ

「書くことで人の役にたつ」をモットーに活動中。
本職はプログラマで、Pythonが得意。
基本情報技術者試験合格。

コメント

コメントする

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)