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

DRF使用普通Serializer时validated_data字段被source值替换问题求解

问题原因

该问题由两处配置错误导致:

  1. ProgramSerializer中的rules字段设置了source='priority_set',DRF反序列化时会将验证后的参数自动存入source指定的priority_set键中,导致validated_data中没有rules字段
  2. PrioritySerializer中的rule_id设置了source='rule.id',反序列化时会将入参的rule_id转换为嵌套的{'rule': {'id': xx}}结构,不符合预期

修改方案

第一步:调整PrioritySerializer区分读写字段

设置字段读写权限,反序列化时仅接收rule_id,避免生成嵌套结构:

class PrioritySerializer(serializers.Serializer):
    # 反序列化写入专用字段
    rule_id = serializers.IntegerField(write_only=True)
    # 序列化输出专用字段,只读模式不参与反序列化
    rule_name = serializers.CharField(source='rule.name', read_only=True)
    rule_rule = serializers.CharField(source='rule.rule', read_only=True)
    priority = serializers.IntegerField(read_only=True)

第二步:修改ProgramSerializer拆分序列化/反序列化逻辑

移除rules字段的source配置,新增to_representation方法兼容原有GET请求的返回结构,同时修正id字段为只读(创建程序无需传入ID):

class ProgramSerializer(serializers.Serializer):
    # 设为只读,创建资源时不需要传入
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=32)
    description = serializers.CharField(style={'base_template': 'textarea.html'}, allow_blank=True)
    # 移除source配置,反序列化时参数直接存入validated_data的rules键
    rules = PrioritySerializer(many=True)

    # 重写序列化逻辑,保证GET请求返回和原有结构完全一致的规则列表
    def to_representation(self, instance):
        rep = super().to_representation(instance)
        rep['rules'] = PrioritySerializer(instance.priority_set.order_by('priority').all(), many=True).data
        return rep

    def create(self, validated_data):
        rules_data = validated_data.pop('rules')
        program_obj = Program.objects.create(**validated_data)

        priority = 0
        for rule in rules_data:
            # 现在rules_data是标准字典列表,直接取rule_id即可
            rule_obj = Rule.objects.get(pk=rule['rule_id'])
            priority += 1
            Priority.objects.create(program=program_obj, rule=rule_obj, priority=priority)

        return program_obj

可选优化:调整视图POST逻辑

创建资源时不需要partial=True参数(该参数仅用于部分更新场景),可移除:

def post(self, request, format=None):
    serializer = ProgramSerializer(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)

修改完成后,validated_data的结构就和预期完全一致,且GET请求的返回结果和原有逻辑没有差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 18:36:03