Django

【実例付】Django Userモデルをカスタマイズする方法

(最終更新月:2022年3月)

✔このような方へ向けて書かれた記事となります

「デフォルトのユーザーモデルを変更したい!どんな方法があるの?」

「独自のユーザーモデルを作成する方法は?」

「ユーザーモデルを拡張したい。新たなフィールドを付け足す方法は?」

✔当記事を通じてお伝えすること

  • ユーザモデルとは?|一般的なモデルとの違いを解説
  • 独自のユーザーモデルを作成する方法を解説
  • ユーザーモデルを拡張する方法を解説

独自のユーザーモデルを作成し、「Eメールアドレスによる認証方法」へ変更する方法をお伝えします。

✔独学におすすめ

ユーザモデルとは?|一般的なモデルとの違いを解説

ユーザーモデルとは?

ここでいうユーザーモデルとは、通常作成するモデルとは違い、Djangoアプリの認証で使われるモデルのことを言います。

セキュリティ性の高い認証システムは、Djangoの特長の一つです。

下記のコマンドでユーザーモデルクラスをインポートとし使用することが可能になります。

from django.contrib.auth.models import User

もしくは、カスタマイズしたユーザーモデルクラスを使用する場合などに備えて、下記のコマンドも覚えておきましょう。

from django.contrib.auth import get_user_model
User = get_user_model()

get_user_modelメソッドを使うことで、アプリ内で実際に使われているユーザーモデルが変数「User」に格納されます。

私はユーザーモデルをカスタマイズすることが多いのでこちらの方法を使っています。

デフォルトのユーザーモデルを見てみる

デフォルトのユーザーモデルは、AbstractUserクラスを継承し、下記のフィールドが用意されています。

デフォルトユーザーのフィールド

  • username
  • first_name
  • last_name
  • email
  • is_staff
  • is_active
  • date_joined

認証で使われるフィールドはモデル内の「USER_NAME_FIELD」で下記のように指定されています。

USERNAME_FIELD = "username"

詳しくは、こちらのgithubページからご覧ください。

ユーザーモデルを変更したい時にできること2つ

こちらのユーザーモデルを変更したい場合、下記の2つの方法があります。

  1. 独自のユーザーモデルを作成する
  2. 外部キーを使って拡張や別のモデルと紐付けする

ポイントとしては、認証方法自体を変更したいのかどうかで上記のどちらを使うかが決まります。

独自ユーザーモデルを作成する

認証方法自体を変更したい場合はこちらの方法が適しています。

なぜなら、適用したい認証方法に合わせたモデルクラスを使用できるから。

例えば、以下のようなときです。

  • Eメールアドレスでのログイン方法にしたい場合
  • IDによるログイン方法にしたい場合

デメリットとしては、モデルクラス自体を書き換えるので手間がかかることです。

外部キーを使って拡張や紐付けをする

認証方法とは関係なく、以下のような場合はこちらの方法が適しています。

  • ユーザーフィールドを追加したい
  • 特定のモデルにユーザーモデルを紐付けたい

あくまでも既存のユーザーモデルを拡張させることになるので、さほど複雑な処理はありません。

こちらもやり方は2通りです。

  1. OneToOneFieldを使う
  2. ForeignKeyを使う

OneToOneFieldを使うのは、ユーザーモデルと1対1の関係となるプロフィールクラスを定義する場面などが適しています。

ForeignKeyを使うのは、例えば「ツイートを発信したのがどのユーザーであるか」「注文をしたのがどのユーザーか」などユーザーと紐付けをしたい場合などが適しています。

これより以上の方法をそれぞれ解説していきます。

  • ①独自のユーザーモデルを作成する方法
  • ②外部キーを使ってユーザーモデルを拡張、ユーザーモデルと紐づける方法

独自のユーザーモデルを作成する方法を解説

まずは、①独自のユーザーモデルを作成する方法を解説します。

流れは下記のとおりです。

  1. ユーザーモデルクラスの属するappを作成し、設定する
  2. モデルクラスを作成する
  3. モデルクラスを操作するモデルマネジャークラスを作成する
  4. モデルクラスとモデルマネジャーを紐付ける
  5. データベースへ作成したモデルを書き込む
  6. Djangoのユーザー認証で使用することを宣言する

ユーザー認証のためのアプリを作成・設定

「accounts」というappを作成、設定します。

ターミナルで下記の通りappを作成します。

python manage.py startapp accounts

settings.pyへ下記を追記します。

INSTALLED_APPS = [
    #....,
    #....,
    "accounts",
]

オリジナルのユーザーモデルを作成

AbstractBaseUser」クラスを継承して、新たなユーザーモデルクラスを作成します。

accounts > models.py

from django.db import models
from django.contrib.auth.models import AbstractBaseUser

class User(AbstractBaseUser):
    pass

継承元のインポートとオリジナルユーザーモデルクラス「User」を作成しました。

認証の為のユーザーモデルです。フィールドは下記の通り最低限とします。

  1. email
  2. active
  3. staff
  4. admin

id」「password」「last_login」の3つは既に備わっています。

オリジナルモデル「User」に上記のフィールドを追加していきます。

from django.db import models
from django.contrib.auth.models import AbstractBaseUser

class User(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='Eメールアドレス',
        max_length=255,
        unique=True,
    )
    active = models.BooleanField(default=True)
    staff = models.BooleanField(default=False) 
    admin = models.BooleanField(default=False) 

これだけでは、機能しません。

USERNAME_FIELD」や設定しておくべきメソッドもあるので下記のとおりとします。

class User(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='Eメールアドレス',
        max_length=255,
        unique=True,
    )
    active = models.BooleanField(default=True)
    staff = models.BooleanField(default=False) 
    admin = models.BooleanField(default=False) 
   
    USERNAME_FIELD = 'email'

    def __str__(self):             
        return self.email

    def has_perm(self, perm, obj=None):
        return self.admin

    def has_module_perms(self, app_label):
        return self.admin

    @property
    def is_staff(self):
        return self.staff

    @property
    def is_admin(self):
        return self.admin

    @property
    def is_active(self):
        return self.active

ユーザーモデルクラスは以上です。

フィールドはご自由にカスタマイズしてください。ただし、このユーザーモデルでは最低限にとどめておくことをオススメします。

モデルは作りましたが、まだこのままでは不十分です。

ユーザーを操作するためのメソッド「create_user」等を作成する必要があります。

モデルマネジャーの定義と紐づけ

ユーザーモデルをカスタマイズする際は、モデルクラスのみならず、モデルマネジャーもカスタマイズする必要があります。

先ほど作成した「User」クラスの上に、「BaseUserManager」クラスを継承したマネジャークラスを作っていきます。

from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser

class UserManager(BaseUserManager):
    def create_user(self, email, password=None):
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_staffuser(self, email, password):
        user = self.create_user(
            email,
            password=password,
        )
        user.staff = True
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password):
        user = self.create_user(
            email,
            password=password,
        )
        user.staff = True
        user.admin = True
        user.save(using=self._db)
        return user

ここでは、ユーザーを作成するメソッドを作っています。

モデルクラスとモデルマネジャーを紐付ける

どちらも完成しましたら、モデルマネジャー「UserManger」とモデル「User」を紐付けます。

下記をモデル内に追加します。

objects = UserManager()

参考までにこれまでのコード全体は下記の通りです。

accounts > models.py

from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser

class UserManager(BaseUserManager):
    def create_user(self, email, password=None):
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_staffuser(self, email, password):
        user = self.create_user(
            email,
            password=password,
        )
        user.staff = True
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password):
        user = self.create_user(
            email,
            password=password,
        )
        user.staff = True
        user.admin = True
        user.save(using=self._db)
        return user

class User(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='Eメールアドレス',
        max_length=255,
        unique=True,
    )
    active = models.BooleanField(default=True)
    staff = models.BooleanField(default=False) 
    admin = models.BooleanField(default=False) 
   
    USERNAME_FIELD = 'email'

    objects = UserManager()

    def __str__(self):             
        return self.email

    def has_perm(self, perm, obj=None):
        return self.admin

    def has_module_perms(self, app_label):
        return self.admin

    @property
    def is_staff(self):
        return self.staff

    @property
    def is_admin(self):
        return self.admin

    @property
    def is_active(self):
        return self.active

マイグレーションの実行

以上でユーザーモデルのコードは完成です。

データベースへモデルを書き込んでいきます。

$ python manage.py makemigrations
Migrations for 'accounts':
  accounts/migrations/0001_initial.py
    - Create model User

$ python manage.py migrate
Operations to perform:
  Apply all migrations: accounts, admin, auth, contenttypes, nippo, sessions
Running migrations:
  Applying accounts.0001_initial... OK

エラー等がなければ次へ進みましょう。

作成したモデルクラスをユーザー認証用として使う

データベースへの書き込みも終わりましたが、今のままでは、作成した「User」モデルは単なる一モデルクラスでしかありません。

実際に認証用として使うことを宣言する必要があります。

settings.pyで下記を追記します。

AUTH_USER_MODEL = 'accounts.User'

settings.pyに変更を加えたので、再度migrateのみで良いので実行しましょう

$ python manage.py migrate

エラーが出なければ、無事完了です。

最後に確認の意味も含めてスーパーユーザーを作ります。

【確認】スーパーユーザーを作成しよう!

ターミナルでスーパーユーザー作成の為のコマンドを入力します。

$ python manage.py createsuperuser
Eメールアドレス: 

通常だと、「ユーザー名」から始まりますがオリジナルユーザーモデルで指定した通り「Eメールアドレス」が認証用で使われている事がわかります。

ログイン画面もこの通りです。

以上で独自のユーザーモデルクラスは完成しました。

ただこのまま進むと、Adminページでうまく操作ができません。

続きは下記の記事で解説をしています。

ユーザーモデルを拡張する方法を解説

主に使用する外部キーは下記の2つです。

  1. OneToOneField
  2. ForeignKey

これらのコードは複雑ではありませんので例をご覧いただきながら解説します。

OneToOneFieldを使う

OneToOneFieldを使ったサンプルです。

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    username = models.CharField(max_length=100, verbose_name="ユーザー名")
    department = models.CharField(max_length=100, blank=True, null=True, verbose_name="部署")
    phone_number = models.IntegerField(blank=True, null=True, verbose_name="携帯番号")
    gender = models.CharField(max_length=1, choices=[(None, "--"), ("m", "男性"), ("f", "女性")], default=None, verbose_name="性別", blank=True, null=True)
    birthday = models.DateField(blank=True, null=True, verbose_name="生年月日")

    def __str__(self):
        return self.username

詳しくはこちらで解説しています↓

ForeignKeyを使う

ForeignKeyを使ったサンプルです。

from django.db import models
from django.contrib.auth import get_user, get_user_model

User = get_user_model()

class NippoModel(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=100, verbose_name="タイトル")
    content = models.TextField(max_length=1000, verbose_name="内容")
    timestamp = models.DateTimeField(auto_now_add=True)

詳しくはこちらで解説しています↓

まとめ

当記事の内容をまとめます。

ユーザーモデルとは、Djangoアプリの認証で使われるモデルのことを言います。

Djangoにはユーザーモデルがデフォルトで用意されておりそのまま使うことも可能です。

ただ、作成しているアプリによっては変更する必要もあります。

変更する方法は下記の通りです。

  1. 独自のユーザーモデルを作成する
  2. 外部キーを使って拡張や別のモデルと紐付けする

それぞれの方法については上記にございますので必要な時にいつでもご覧ください。

また、このまま進んでもAdminページでうまく操作ができません。

続きは下記の記事で解説をしています。