使用Django Signal与Djoser创建用户时遭遇400 Bad Request错误
自定义Djoser用户创建流程400错误排查与解决
问题根源梳理
- 序列化器语法错误:
fields列表中phone_number后缺失逗号,导致字段解析失败,直接触发400错误。 - 信号参数传递失效:
post_save信号无法接收serializer.save()传入的额外参数——Djoser默认save方法仅处理User模型字段,非模型字段不会传递到信号的kwargs中。 - 视图错误处理缺失:自定义
register视图未处理序列化器验证失败的情况,直接返回201状态码,无法暴露具体错误原因。 - 数据一致性风险:原信号逻辑未使用事务,若关联模型创建失败,会出现User已创建但关联数据缺失的不一致状态。
分步解决方案
1. 修复序列化器语法错误
修改accounts.serializers.py的fields列表,在phone_number后添加逗号:
class Meta(BaseUserCreateSerializer.Meta): model = User fields = ( "id", "email", "user_role", "password", "first_name", "middle_name", "last_name", "date_of_birth", "gender", "relationship_status", "phone_number", # 补全缺失的逗号 "address_line_one", "address_line_two", "address_line_three", "province", "barangay", "city", "zip_code", )
2. 重写序列化器save方法,原子化创建关联模型
抛弃不可靠的信号传递,在序列化器中通过事务原子性创建所有关联模型,确保数据一致性:
from djoser.serializers import UserCreateSerializer as BaseUserCreateSerializer from django.contrib.auth import get_user_model from rest_framework import serializers from django.db import transaction from .models import AddressDetails, UserProfile User = get_user_model() class UserCreateSerializer(BaseUserCreateSerializer): address_line_one = serializers.CharField(write_only=True, required=False) address_line_two = serializers.CharField(write_only=True, required=False) address_line_three = serializers.CharField(write_only=True, required=False) province = serializers.CharField(write_only=True, required=True) barangay = serializers.CharField(write_only=True, required=True) city = serializers.CharField(write_only=True, required=True) zip_code = serializers.CharField(write_only=True, required=True) first_name = serializers.CharField(write_only=True, required=True) middle_name = serializers.CharField(write_only=True, required=True) last_name = serializers.CharField(write_only=True, required=True) date_of_birth = serializers.DateField(required=True) gender = serializers.CharField(write_only=True, required=True) relationship_status = serializers.CharField(write_only=True, required=True) phone_number = serializers.CharField(write_only=True, required=True) class Meta(BaseUserCreateSerializer.Meta): model = User fields = ( "id", "email", "user_role", "password", "first_name", "middle_name", "last_name", "date_of_birth", "gender", "relationship_status", "phone_number", "address_line_one", "address_line_two", "address_line_three", "province", "barangay", "city", "zip_code", ) @transaction.atomic def save(self, **kwargs): # 创建User实例 user = super().save(**kwargs) # 提取地址数据并创建AddressDetails address_data = { key: self.validated_data.get(key, "") for key in ["address_line_one", "address_line_two", "address_line_three"] } address_data.update({ "province": self.validated_data["province"], "barangay": self.validated_data["barangay"], "city": self.validated_data["city"], "zip_code": self.validated_data["zip_code"], }) address = AddressDetails.objects.create(**address_data) # 创建UserProfile实例 UserProfile.objects.create( user=user, **{ key: self.validated_data[key] for key in ["first_name", "middle_name", "last_name", "date_of_birth", "gender", "relationship_status", "phone_number"] }, address_details=address ) return user
3. 修复视图错误处理逻辑
如果使用自定义register视图,必须返回序列化器验证失败的具体错误信息:
from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import status from .serializers import UserCreateSerializer @api_view(["POST"]) def register(request): serializer = UserCreateSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) # 验证失败时返回具体错误 return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
4. 清理不必要的信号代码
由于已在序列化器中直接处理关联模型创建,可删除accounts.signals.py中的信号接收器代码,避免逻辑冲突。
测试验证
- 确保Djoser配置指向修改后的序列化器:
# config.settings.py DJOSER = { "SERIALIZERS": { "user_create": "accounts.serializers.UserCreateSerializer", # 其他Djoser配置... } } - 使用Postman发送POST请求到
/users/,请求体包含所有必填字段,验证返回201状态码,且数据库中User、AddressDetails、UserProfile均成功创建。
内容的提问来源于stack exchange,提问作者juanl4zy
相关产品推荐
相关产品推荐

