【Django】独自ユーザーモデルの作成(カスタムUserモデル:AbstractBaseUser)
2021.12.14 /
本記事ではDjangoで独自のユーザーモデルを作成する方法について解説していきます。
Djangoには標準でUserモデルが用意されています。しかしほとんどの場合で作成するWebアプリケーションに合わせてUserモデルをカスタマイズする必要があります。
カスタムUserモデルを作成する方法はいくつかありますが、ここでは最も自由度が高いAbstractBaseUserを継承して作成する方法について詳しく解説していきます。
デフォルト(標準)のUserモデル
Djangoには標準で利用できるUserモデルが用意されています。このUserモデルはdjango.contrib.auth.models.Userに次のように定義されています。
class User(AbstractUser):
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'
標準UserモデルはAbstractUserを継承していることがわかります。
そのため標準Userモデルでは以下に示すAbstractUserで定義されているカラムが定義されます。
username = models.CharField()
first_name = models.CharField()
last_name = models.CharField()
email = models.EmailField()
is_staff = models.BooleanField()
is_active = models.BooleanField()
date_joined = models.DateTimeField()
カラム名 | 説明 |
---|---|
username | ユーザー名 |
first_name | 名前 |
last_name | 苗字 |
メールアドレス | |
is_staff | 管理画面のアクセス可否 |
is_active | ログインの可否 |
date_joined | アカウントの作成日時 |
Djangoのチュートリアルなどでは、この標準Userモデルを利用して開発を進めることが多いです。
カスタムUserモデルの作成
カスタムUserモデルを作成する理由
Djangoの標準Userモデルはインストール後すぐに利用することができるため、Django初心者の方が利用するにはとても便利です。
しかし独自のWebアプリケーションを作成する場合、ユーザー情報に必要な項目は標準Userモデルと異なるのが普通です。
またログインにusernameではなくemailを利用したい場合もあります。
そのため大抵の場合、UserモデルをWebアプリケーションに合わせてカスタマイズする必要があるのです。
django公式サイトでも、カスタムユーザーモデルを利用することを強く推奨しています。
カスタムUserモデルの作成方法
ユーザーモデルをカスタマイズする方法は以下3つの方法があります。
- 標準Userモデルと1対1の関係を持つモデルを作成
- AbstractUserを継承したモデルを作成
- AbstractBaseUserを継承したモデルを作成
標準Userモデルと1対1の関係を持つモデルを作成
例えば次のように標準Userモデルと1対1の関係を持つモデルを作成し、ユーザー情報に追加したいフィールドをそこに書き込みます。
class UserAddInfo(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
department = models.CharField()
image = models.ImageField()
このように標準のUserモデルを活かしたまま、新しい情報をUserモデルに追加できます。
しかしこの方法では既存のカラム(first_nameやlast_nameなど)を必ず利用しなければならないですし、ログインをemailに変更することもできないです。
またテーブルが複数に分かれることにより、Webアプリケーションのパフォーマンスが悪くなることが考えられます。
これらの理由より、標準Userモデルと1対1の関係を持つモデルを作成することはお勧めしません。
AbstractUserを継承したモデルを作成
AbstractUserは標準Userモデルが継承して利用しているモデルです。
AbstractUserモデルはdjango.contrib.auth.modelsで以下のように定義されています。
class AbstractUser(AbstractBaseUser, PermissionsMixin):
username_validator = UnicodeUsernameValidator()
username = models.CharField(_('username'), max_length=150, unique=True,…)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=150, blank=True)
email = models.EmailField(_('email address'), blank=True)
is_staff = models.BooleanField(_('staff status'), default=False,…)
is_active = models.BooleanField(_('active'), default=True,…)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = UserManager()
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
abstract = True
AbstractUserはAbstractBaseUserとPermissionsMixinを継承しています。
上記AbstractUserモデルを継承してカスタムUserモデルを作成するため、「標準Userモデルと1対1の関係を持つモデルを作成」と大きな違いはないです。
テーブルが複数に分かれることはないので、パフォーマンス面で不利になることはありません。しかしカラム(属性)の追加しかできないのでモデルの柔軟性は低いです。
標準Userモデルにカラム(フィールド)の追加のみしたい場合はこちらの方法を利用します。
AbstractBaseUserを継承したモデルを作成
AbstractBaseUserはdjango.contrib.auth.base_userで以下のように定義されています。
class AbstractBaseUser(models.Model):
password = models.CharField(_('password'), max_length=128)
last_login = models.DateTimeField(_('last login'), blank=True, null=True)
is_active = True
REQUIRED_FIELDS = []
_password = None
class Meta:
abstract = True
AbstractBaseUserはdjango.db.models.Modelを継承しています。
AbstractBaseUserには認証機能のみが含まれており、独自でフィールドを設定することができます。
つまり認証以外の部分はなにも実装されていないクラスであり、first_nameやlast_nameといった必要のないフィールドをUserモデルで使わないで済むのです。
AbstractBaseUserを継承したUserモデルは作成が少々面倒ではありますが、カスタマイズの柔軟性は非常に高いです。
ここまでのモデルの継承関係は次図のようになります。
AbstractBaseUserを継承したUserモデルの作成
ここではカスタマイズの柔軟性が高く、自由度があるAbstractBaseUserを継承したUserモデルの作成方法を解説していきます。
カスタムUserモデルは以下の流れで作成していきます。
- アプリケーションの生成
- カスタムUserモデルの作成
- カスタムUserManagerの作成
- 認証モデルの変更
- マイグレーションの実行
- 管理画面の設定
カスタムUserモデルを利用する場合は、Djangoプロジェクトを作成後すぐに設定する必要があります。migrateを実行した後ではUserモデルの変更は非常に難しいです
またここで作成するUserモデルは、ログイン認証にユーザー名ではなく、メールアドレスを利用するように変更します。
1.アプリケーションの生成
まずはユーザー管理用のアプリケーションを作成します。manage.py startappコマンドでusersアプリケーションを作成しましょう。
python manage.py startapp users
プロジェクトフォルダ内のsettings.pyのINSTALLED_APPS欄に生成したアプリケーションを追加します。
INSTALLED_APPS = [
'…',
'users.apps.UsersConfig',
]
2.カスタムUserモデルの作成
次にカスタムUserモデルを作成していきます。
作成したアプリケーション内のmodels.pyを以下のように変更します。django.contrib.auth.models.AbstractUserを元にして作成しています。
from django.db import models
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.core.mail import send_mail
from django.utils import timezone
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.utils.translation import gettext_lazy as _
class User(AbstractBaseUser, PermissionsMixin):
username_validator = UnicodeUsernameValidator()
username = models.CharField(_("username"), max_length=50, validators=[username_validator], blank=True)
email = models.EmailField(_("email_address"), unique=True)
is_staff = models.BooleanField(_("staff status"), default=False)
is_active = models.BooleanField(_("active"), default=True)
date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
objects = UserManager()
USERNAME_FIELD = "email"
EMAIL_FIELD = "email"
REQUIRED_FIELDS = ['username']
class Meta:
verbose_name = _("user")
verbose_name_plural = _("users")
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)
objects
Userモデルで設定しているobjects変数は、views.pyでUserモデルの情報を取得する際などで利用します。
user = User.objects.get(username="office54")
objects変数に指定するクラス(ここではUserManager())は、ターミナルでユーザーを作成(manage.py createsuperuserなど)する際に呼ばれます。
USERNAME_FIELD
USERNAME_FIELDで指定したフィールドは、ログイン認証やメール送信などで利用します。
ここをemailにすることでメールアドレスでのログインが可能になります。
指定したフィールドは一意である必要があるため、ここで指定できるフィールドはunique=Trueである必要があります。
EMAIL_FIELD
ターミナルでユーザー作成(manage.py createsuperuser)するときに表示される項目です。
ユーザーは指定した項目の値を入力するよう求められます。
複数のフィールドを設定することができます。
3.カスタムUserManagerの作成
ターミナルでユーザーを作成(manage.py createsuperuserなど)する際に呼ばれるUserManagerを、カスタムUserモデル用に書き換えます。
UserManagerクラスには_create_user関数とcreate_user関数、create_superuserの3つがあります。それぞれユーザーを新規で作成する際に呼ばれる関数です。
class User(AbstractBaseUser, PermissionsMixin)の上部に以下を追記します。
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, username, email, password, **extra_fields):
if not email:
raise ValueError('Emailを入力して下さい')
email = self.normalize_email(email)
username = self.model.normalize_username(username)
user = self.model(username=username, email=email, **extra_fields)
user.set_password(password)
user.save(using=self.db)
return user
def create_user(self, username, 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, username, 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('is_staff=Trueである必要があります。')
if extra_fields.get('is_superuser') is not True:
raise ValueError('is_superuser=Trueである必要があります。')
return self._create_user(username, email, password, **extra_fields)
emailは必須項目なので、emailが空の場合は例外が発生するようにしています。
4.認証モデルの変更
カスタムUserモデルを認証機能で使用する認証モデルに変更します。
以下のようにsettings.pyにAUTH_USER_MODELにアプリケーション名.モデル名を指定した設定を追加します。
AUTH_USER_MODEL = 'users.User'
5.マイグレーションの実行
マイグレーションを実行して、作成したカスタムUserモデルをデータベースに反映させます。
python manage.py migrations
python manage.py migrate
6.管理サイトの設定
管理サイトでカスタムUserモデルを利用できるようにするため、admin.pyを以下のように変更します。
またUserCreationFormやUserChangeFormもそのまま利用することができないため、専用フォームを用意しています。
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.utils.translation import ugettext_lazy as _
from .models import User
class MyUserChangeForm(UserChangeForm):
class Meta:
model = User
fields = '__all__'
class MyUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('email','username')
class MyUserAdmin(UserAdmin):
fieldsets = (
(None, {'fields': ('email', 'password', 'username')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
'groups', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2'),
}),
)
form = MyUserChangeForm
add_form = MyUserCreationForm
list_display = ('email', 'username', 'is_staff')
list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups')
search_fields = ('email', 'username')
ordering = ('email',)
admin.site.register(User, MyUserAdmin)
まとめ
本記事「【Django】独自ユーザーモデルの作成(カスタムUserモデル:AbstractBaseUser)」はいかがでしたか。
標準で用意されているUserモデルでは自由にWebアプリケーションが作成できません。
柔軟にカスタマイズができるカスタムUserモデルを作れるようにして、作成できるWebアプリケーションの幅を広げてください。