View on GitHub

サインアップビューの作成

Home

サインアップビューの作成

シリアライザ

src/backend/api/accounts/serializers.py

from rest_framework import serializers
from rest_framework_simplejwt.tokens import RefreshToken
from django.contrib.auth.hashers import make_password
from django.db import transaction, IntegrityError

from api.accounts.models import CustomUser
from api.online.models import User
from api.online.utils import hash


class SignUpSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True)

    def validate(self, attrs):
        email = attrs["email"]
        hashed = hash(email)

        # すでに同じ email_hash が存在したら登録不可
        if User.objects.filter(email_hash=hashed).exists():
            raise serializers.ValidationError("このメールアドレスは既に登録されています。")

        attrs["email_hash"] = hashed
        return attrs

    def create(self, validated_data):
        email = validated_data["email"]
        password = validated_data["password"]
        hashed = validated_data["email_hash"]

        try:
            with transaction.atomic():
                # 1. online.User を作成(暗号化+ハッシュ)
                profile = User()
                profile.set_email(email)  # 内部で encrypt + email_hash を設定
                profile.save()

                # 2. CustomUser を作成
                custom_user = CustomUser.objects.create(
                    username=hashed,
                    password=make_password(password),
                    user=profile,
                )
        except IntegrityError:
            raise serializers.ValidationError("このメールアドレスは既に登録されています。")

        # 3. JWT 発行
        refresh = RefreshToken.for_user(custom_user)

        return {
            "access": str(refresh.access_token),
            "refresh": str(refresh),
            "user": {
                "user_id": str(profile.user_id),
                # "email": profile.get_email()
            },
        }

ビュー

src/backend/api/accounts/views.py

from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework import status

from .serializers import SignUpSerializer


class SignUpView(APIView):
    permission_classes = (AllowAny,)

    def post(self, request):
        serializer = SignUpSerializer(data=request.data)
        if serializer.is_valid():
            data = serializer.save()
            return Response(data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

URL マッピング

src/backend/api/accounts/urls.py

from django.urls import path
from .views import SignUpView

urlpatterns = [
    path("signup/", SignUpView.as_view(), name="accounts-signup"),
]

src/backend/config/urls.py

from django.contrib import admin
from django.urls import path, include  # <- includeを追加

urlpatterns = [
    path('admin/', admin.site.urls),
    path("api/accounts/", include("api.accounts.urls")),  # <- 追加
]

実行確認

バックエンドサーバが起動している状態で、ブラウザで下記 URL にアクセスしてください。

Contentフォームに、例えば下記のデータを入力し、POSTボタンをクリックしてください。

{
  "email": "foo@example.com",
  "password": "secret123"
}

下記のようにレスポンスが返ってきたら OK。

HTTP 201 Created
Allow: POST, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "access": "<ACCESS_TOKEN>",
    "refresh": "<REFRESH_TOKEN>",
    "user": {
        "user_id": "<USER_ID>"
    }
}

t_usersテーブルに下記のようにユーザデータが登録されました。

recsys_full=# SELECT * FROM t_users;
               user_id                |                                           email_encrypted                                            |                            email_hash
--------------------------------------+------------------------------------------------------------------------------------------------------+------------------------------------------------------------------
 <USER_ID>                            | <ENCRYPTED_EMAIL_ADDRESS>                                                                            | <HASH_OF_EMAIL_ADDRESS>
(1 row)

recsys_full=# SELECT id, user_id FROM accounts_customuser;
 id |               user_id
----+--------------------------------------
  1 | <USER_ID>
(1 row)