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
相关产品推荐
相关产品推荐

