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

Django REST Framework嵌套JSON同时创建用户与疾病实例问题排查

解决Django REST Framework创建用户时同步创建关联Disease实例的问题

问题现状

需要实现API在创建MyUser实例的同时,同步创建关联的Disease实例,但当前请求返回400错误,响应提示:

{
  "user_disease": [
    "This field is required."
  ]
}

请求体中的disease字段数据无法被序列化器识别,且关联的疾病实例未被创建。

问题排查

  1. 序列化器字段名不匹配:
    序列化器中定义的嵌套字段是user_disease,但请求体传递的是disease,导致序列化器无法找到对应数据,触发必填字段校验错误。

  2. create方法未正确处理关联数据:
    当前create方法直接创建用户,未提取并处理疾病数据;注释代码不仅键名错误(用了disease而非user_disease),创建Disease的语法也有误,外键参数需以user=user形式传递。

  3. 用户密码处理不当:
    使用MyUser.objects.create(**validated_data)创建用户时,密码会以明文存储,无法正常验证身份,应使用create_user自动处理密码哈希。

  4. 冗余方法无效:
    SignUpAPIView继承自APIView,perform_create方法不会被框架调用,属于冗余代码。

解决方案

1. 修改序列化器(accounts/serializers.py)

调整字段名与请求体一致,正确实现嵌套数据的创建逻辑:

class DiseaseSerializer(serializers.ModelSerializer):
    class Meta:
        model = Disease
        fields = ['arrhythmia']  # 根据实际业务需求添加其他疾病字段

class MyUserSerializer(serializers.ModelSerializer):
    # 字段名与请求体的"disease"保持一致
    disease = DiseaseSerializer(many=False, read_only=False)

    class Meta:
        model = MyUser
        # 明确指定业务所需字段,避免包含AbstractUser的敏感/不必要字段
        fields = [
            'identifier', 'password', 'username', 'email', 'birth', 
            'gender', 'isForeigner', 'height', 'weight', 
            'pw_queiston_idx', 'pw_answer', 'disease'
        ]

    def create(self, validated_data):
        # 从验证数据中取出疾病相关数据
        disease_data = validated_data.pop('disease')
        # 使用create_user创建用户,自动处理密码哈希
        user = MyUser.objects.create_user(**validated_data)
        # 创建关联的Disease实例,绑定到当前用户
        Disease.objects.create(user=user, **disease_data)
        return user

2. 修正视图(accounts/views.py)

删除无用的perform_create方法,保持代码简洁:

class SignUpAPIView(APIView):
    permission_classes = [AllowAny]

    def post(self, request):
        serializer = MyUserSerializer(data=request.data)
    
        if serializer.is_valid():
            user = serializer.save()

            # 生成JWT Token对
            token = TokenObtainPairSerializer.get_token(user)
            refresh_token = str(token)
            access_token = str(token.access_token)

            res = Response(
                {
                    "user": serializer.data,
                    "message": "sign_up success",
                    "token": {
                        "access": access_token,
                        "refresh": refresh_token
                    }
                },
                status=status.HTTP_201_CREATED
            )

            # 将Token存入HttpOnly Cookie
            res.set_cookie("access", access_token, httponly=True)
            res.set_cookie("refresh", refresh_token, httponly=True)

            return res
        else:
            print("is_valid() is false!")
    
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

关键修改说明

  • 字段名对齐:序列化器嵌套字段名改为disease,与请求体键匹配,解决必填字段报错问题。
  • 密码安全:使用create_user替代create,自动对密码哈希处理,保证账号安全。
  • 关联创建:先创建用户实例,再以用户为外键创建Disease,确保关联关系正确建立。
  • 字段明确:避免使用fields = '__all__',明确指定业务字段,减少不必要的字段暴露或错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 14:33:08