LoginSignup
0
0

DRF カスタムユーザー

Last updated at Posted at 2023-07-28

はじめに

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 
config/settings.py
  INSTALLED_APPS = [
      ---省略---
+     "accounts.apps.AccountsConfig",
  ]

カスタムユーザー/マネージャーの作成

django.contrib.auth.base_user.AbstractBaseUserを継承したカスタムユーザーのクラスを作成し、必要なフィールド情報を設定します。

accounts/models.py
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にカスタムユーザーを利用するための設定を追加します。

config/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を必須にします。

ログイン.png

GET /user/

レスポンスボディーの内容を変更します。

ユーザー.png

変更内容

dj_rest_auth.serializers.LoginSerializerを継承して修正します。

accounts/serializers.py
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で指定します。

config/settings.py
  # dj-rest-auth
  REST_AUTH = {
      "USE_JWT": True,
+     "LOGIN_SERIALIZER": "accounts.serializers.LoginSerializer",
+     "USER_DETAILS_SERIALIZER": "accounts.serializers.UserDetailsSerializer",
  }
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0