サインアップビューの作成
シリアライザ
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)