はじめに
dj_rest_auth
を導入したDRFのプロジェクトにカスタムユーザーの設定を行います。
環境
- Intel Mac 13.4.1(c)
- Python 3.11.4
- Django 4.2.3
- DRF 3.14.0
- dj-rest-auth 4.0.1
やりたいこと
- ユーザーのIDをUUIDにする。
- メールアドレス+パスワードでログインでする。
- ユーザーの属性は
first_name
,last_name
ではなくnick_name
にする。 - ログイン画面のリクエスト項目から
username
を除去する - ユーザー情報のレスポンス項目を変更する
-
pk
属性の名前をid
にする - 返却するのは
id
,email
,nick_name
-
カスタムユーザー
アカウント用プロジェクトの作成
アカウント用のプロジェクトをaccounts
という名前で作成して、settings.py
に登録します。
$ ./manage.py startapp accounts
INSTALLED_APPS = [
---省略---
+ "accounts.apps.AccountsConfig",
]
カスタムユーザー/マネージャーの作成
django.contrib.auth.base_user.AbstractBaseUser
を継承したカスタムユーザーのクラスを作成し、必要なフィールド情報を設定します。
import uuid
from django.db import models
from django.contrib.auth.models import (
BaseUserManager,
AbstractBaseUser,
PermissionsMixin,
)
class UserManager(BaseUserManager):
def _create_user(self, email, password, **extra_fields):
if not email:
raise ValueError("The given email must be set")
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", False)
extra_fields.setdefault("is_superuser", False)
return self._create_user(email=email, password=password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
return self._create_user(email=email, password=password, **extra_fields)
class User(AbstractBaseUser, PermissionsMixin):
class Meta:
db_table = "user"
# 必要な属性を指定
id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
email = models.EmailField("メールアドレス", unique=True)
nick_name = models.CharField("ニックネーム", max_length=255, blank=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = UserManager()
EMAIL_FIELD = "email"
USERNAME_FIELD = "email"
# `createsuperuser`コマンドで入力するフィールドを追加
REQUIRED_FIELDS = ["nick_name"]
def __str__(self):
return self.email
カスタムユーザーを利用するように設定
settings.py
にカスタムユーザーを利用するための設定を追加します。
+ # カスタムユーザー
+ AUTH_USER_MODEL = "accounts.User"
マイグレーション
マイグレーションしてDBに適用します。
$ ./manage.py makemigrations accounts
$ ./manage.py migrate
作成されたテーブルを確認すると、以下のようになっていました。(SQLite)
$ ./manage.py dbshell
SQLite version 3.32.2 2021-07-12 15:00:17
sqlite> .header on
sqlite> .mode column
sqlite> pragma table_info('user');
cid name type notnull dflt_value pk
---------- ---------- ------------ ---------- ---------- ----------
0 password varchar(128) 1 0
1 last_login datetime 0 0
2 is_superus bool 1 0
3 id char(32) 1 1
4 email varchar(254) 1 0
5 nick_name varchar(255) 1 0
6 is_staff bool 1 0
7 is_active bool 1 0
動作確認
スーパーユーザーを作成してみます。
$ ./manage.py createsuperuser
メールアドレス: admin@example.com
ニックネーム: AdminUser
Password:
Password (again):
Superuser created successfully.
期待通り「ニックネーム」の入力ができました。また、管理サイトのログイン画面も
上記のように「メールアドレス」「パスワード」での入力に変わりました。
dj_authのメッセージ構造を調整
dj_auth
がログイン周りで提供してくれているメッセージ構造を少しだけ変更します。
POST /login/
リクエストボディーからusername
を除去してemail
を必須にします。
GET /user/
レスポンスボディーの内容を変更します。
変更内容
dj_rest_auth.serializers.LoginSerializer
を継承して修正します。
from dj_rest_auth.serializers import LoginSerializer, UserDetailsSerializer
from django.contrib.auth import authenticate, get_user_model
from rest_framework import serializers
UserModel = get_user_model()
class LoginSerializer(LoginSerializer):
username = None
email = serializers.EmailField(required=True, allow_blank=False)
class UserDetailsSerializer(UserDetailsSerializer):
class Meta:
model = UserModel
fields = ("id", "email", "nick_name")
read_only_fields = ("email",)
作成したシリアライザーを利用するようにsettings.py
で指定します。
# dj-rest-auth
REST_AUTH = {
"USE_JWT": True,
+ "LOGIN_SERIALIZER": "accounts.serializers.LoginSerializer",
+ "USER_DETAILS_SERIALIZER": "accounts.serializers.UserDetailsSerializer",
}