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

DRF中如何将partial=True传递给嵌套序列化器?

问题描述

我定义了如下两个Django REST Framework序列化器:

class OuterSerializer():
    inner_obj = InnerSerializer(many=True, required=False)
    # 其他字段......
class InnerSerializer():
    field_1 = CharField()
    field_2 = CharField()

我需要对OuterSerializer对应的模型做局部更新,实现的视图方法如下:

def partial_update(self, request, *args, **kwargs):
    serializer = OuterSerializer(data=request.data, context={'request': self.request}, partial=True)
    serializer.is_valid(raise_exception=True)
    data = serializer.data
    outerobj = self.service_layer.update(kwargs['pk'], data, request.user)
    response_serializer = OpportunitySerializer(instance=outerobj, context={'request': self.request})
    return Response(response_serializer.data, HTTPStatus.OK) 

现在遇到的问题是:partial=True参数无法传递给嵌套的InnerSerializer。比如当请求体为:

{"inner_obj":
  {
    "field_1" : "abc"
  }
}

会返回400错误,提示field_2为必填字段。

我曾尝试在OuterSerializer的__init__方法中设置内层序列化器的partial属性,但无效:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    # 将当前序列化器的上下文传递给嵌套序列化器
    self.fields['inner_obj'].context.update(self.context)
    self.fields['inner_obj'].partial = kwargs.get('partial')  
解决方案

方法1:修正__init__方法,针对many=True的嵌套序列化器设置partial

因为你的inner_obj设置了many=True,所以self.fields['inner_obj']实际上是ListSerializer实例,而非直接的InnerSerializer。需要修改它的child属性的partial值:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    partial = kwargs.get('partial', False)
    # 处理many=True的嵌套序列化器
    inner_serializer = self.fields['inner_obj']
    if hasattr(inner_serializer, 'child'):
        inner_serializer.child.partial = partial
    else:
        inner_serializer.partial = partial
    inner_serializer.context.update(self.context)

方法2:动态修改InnerSerializer字段的required属性

如果只在局部更新场景下需要放松字段校验,可以在OuterSerializer的__init__中,根据当前是否为partial模式,动态修改InnerSerializer里字段的required属性:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    partial = kwargs.get('partial', False)
    if partial:
        # 获取内层序列化器(注意many=True时要取child)
        inner_serializer = self.fields['inner_obj'].child if hasattr(self.fields['inner_obj'], 'child') else self.fields['inner_obj']
        # 将所有字段设为非必填
        for field in inner_serializer.fields.values():
            field.required = False
    self.fields['inner_obj'].context.update(self.context)

方法3:自定义InnerSerializer的校验逻辑

在InnerSerializer中重写validate方法,针对partial模式跳过必填校验:

class InnerSerializer(serializers.ModelSerializer):
    field_1 = serializers.CharField()
    field_2 = serializers.CharField()

    def validate(self, attrs):
        # 从上下文获取partial状态
        partial = self.context.get('partial', False)
        if not partial:
            # 非局部更新时校验field_2必填
            if 'field_2' not in attrs:
                raise serializers.ValidationError({"field_2": "该字段为必填项"})
        return attrs

同时在OuterSerializer的__init__中把partial值传入内层序列化器的上下文:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    partial = kwargs.get('partial', False)
    self.fields['inner_obj'].context.update({'partial': partial, **self.context})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 03:20:51