You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Django Signal与Djoser创建用户时遭遇400 Bad Request错误

自定义Djoser用户创建流程400错误排查与解决

问题根源梳理

  1. 序列化器语法错误:fields列表中phone_number后缺失逗号,导致字段解析失败,直接触发400错误。
  2. 信号参数传递失效:post_save信号无法接收serializer.save()传入的额外参数——Djoser默认save方法仅处理User模型字段,非模型字段不会传递到信号的kwargs中。
  3. 视图错误处理缺失:自定义register视图未处理序列化器验证失败的情况,直接返回201状态码,无法暴露具体错误原因。
  4. 数据一致性风险:原信号逻辑未使用事务,若关联模型创建失败,会出现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中的信号接收器代码,避免逻辑冲突。

测试验证

  1. 确保Djoser配置指向修改后的序列化器:
    # config.settings.py
    DJOSER = {
        "SERIALIZERS": {
            "user_create": "accounts.serializers.UserCreateSerializer",
            # 其他Djoser配置...
        }
    }
    
  2. 使用Postman发送POST请求到/users/,请求体包含所有必填字段,验证返回201状态码,且数据库中User、AddressDetails、UserProfile均成功创建。

内容的提问来源于stack exchange,提问作者juanl4zy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 11:50:55