ユーザーモデルの種類
- User(標準モデル)
- AbstractUser
- AbstractBaseUser(オススメ)
各モデルの違い
標準モデル(難易度低)
簡単だが応用が効かない。
from django.contrib.auth.models import User
AbstractUser(難易度中)
フィールドのカスタマイズ(追加・変更)ができる。
from django.contrib.auth.models import AbstractUser
AbstractBaseUser(難易度高)
フィールドのカスタマイズ(追加・変更・削除)ができる。
from django.contrib.auth.models import AbstractBaseUser
公式推奨
後でユーザーモデルを変更するのは、超大変なので最初からAbstractBaseUserを使うのがオススメだそうです。
チュートリアル等はUser(標準モデル)でも十分です。
初回migrate前にAbstractBaseUserを定義する
プロジェクト開始前にどのタイプにするかよく考える事
デフォルトのフィールド
デフォルトのフィールドを参考にする。
引数はあまり気にせず、どんなフィールドが作られるのかだけを見てもらえればOKです!
この中からよく使われそうな物をピックアップして、さらに新たなフィールドを追加してみたいと思います。
ちなみに、User(標準モデル)
とAbstractUser
を使った場合は、以下のフィールドが作成されます。
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
#最終ログイン日時
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
#スーパーユーザー真偽
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
#ユーザーネーム
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
#ファーストネーム
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
#ラストネーム
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
#メールアドレス
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
#スタッフ権限
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
#ログイン可不可
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
#登録した日時
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
#グループ
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
#パーミッション
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
モデルの作成
とりあえず適当に必要なフィールドを書いちゃいます。
- ユーザーネーム(Twitterの@以降を想定)
- ニックネーム
- 誕生日
- プロフィール画像
- 血液型(choices=のサンプルとして)
- url
- 自己紹介文
- 登録日
- ログインの可否(管理者用)
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
#usernameでバリーデートするために入れときました(無くてもOK)
from django.core.validators import MinLengthValidator, RegexValidator
class MyUser(AbstractBaseUser, PermissionsMixin):
BLOOD_CHOICES = [
("A型","A型"),
("B型","B型"),
("AB型","AB型"),
("O型","O型")
]
username = models.CharField(verbose_name='username', max_length=10, unique=True, validators=[MinLengthValidator(5,), RegexValidator(r'^[a-zA-Z0-9]*$',)])
email = models.EmailField(verbose_name='Email', max_length=50, unique=True)
nickname = models.CharField(verbose_name='ニックネーム', max_length=10, blank=False, null=False)
date_of_birth = models.DateField(verbose_name="誕生日", blank=True, null=True)
image = models.ImageField(verbose_name='プロフィール画像', upload_to="image/", blank=True, null=True)
blood_type = models.TextField(verbose_name="血液型", choices=BLOOD_CHOICES, blank=True, null=True)
url = models.URLField(verbose_name='リンク', blank=True, null=True)
introduction = models.TextField(verbose_name='自己紹介', max_length=300, blank=True, null=True)
date_joined = models.DateTimeField(verbose_name='登録日', auto_now_add=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
#AbstractBaseUserにはMyUserManagerが必要
objects = MyUserManager()
#一意の識別子として使用されます
USERNAME_FIELD = 'email'
#ユーザーを作成するときにプロンプトに表示されるフィールド名のリストです。
REQUIRED_FIELDS = ['username']
def __str__(self):
return self.username
is_activeについて
イメージしやすいように例えるとBAN機能のようなものです。
チェックを外すとそのユーザーがログインできなくなります。
MyUserManager
管理者が管理コマンド上(ターミナル等)でユーザーを作成する時に必要です。次の項目で書きます。
USERNAME_FIELD
ログインする時の一意の識別子です。
Twitterであれば、emailとかusernameになりますね!
unique=Trueのフィールドのみ設定できます。
REQUIRED_FIELDS
管理者が管理コマンド上(ターミナル等)でユーザーを作成する時に表示されるリストです。
上記では'username'だけになっていますが、複数設定することも可能です。
#複数設定する場合はこんな感じ
REQUIRED_FIELDS = ['username', 'date_of_birth']
MyUserManagerの実装
前述の通り、管理者が管理コマンド上(ターミナル等)でユーザーを作成する時に必要なので作成したMyUser(AbstractBaseUser
)の上に書いておく。
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
from django.core.validators import MinLengthValidator, RegexValidator
class MyUserManager(BaseUserManager):
def create_user(self, username, email, password=None):
if not username:
raise ValueError('Users must have an username')
if not email:
raise ValueError('Users must have an email address')
user = self.model(
username=username,
email=self.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, email, password):
user = self.create_user(
username=username,
email=self.normalize_email(email),
password=password,
)
user.is_admin=True
user.is_staff=True
user.is_superuser=True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser, PermissionsMixin):
#省略
大体こんな感じで大丈夫!
変更するとしたらif not hoge:
と同時にuser=
の引数くらいでしょうか?
他はコピペで大丈夫だと思います。
デフォルトのユーザーモデルに上書き
上書きしないとエラーになるのでsetting.py
に設定を書きます。
AUTH_USER_MODEL = 'アプリ名.モデルのクラス名'
#サンプル
AUTH_USER_MODEL = 'accounts.MyUser'
マイグレーションしてみる
$ python manage.py makemigrations
$ python manage.py migrate
スーパーユーザーの作成
スーパーユーザーはmigrate後に作る事
$ python manage.py createsuperuser
まとめ
AbstractBaseUser
はかなり応用が効くみたいで、SNS認証が必要な場合にも使えます。
サービス公開を目的とする場合は是非AbstractBaseUser
を利用してみて下さい!
応用が効きすぎて色んな設定がありますので、詳しく知りたい方は公式ドキュメントを参照してくださいね!