英文:
Passing partial=True down to nested serializer in DRF
问题
以下是您要求的内容的翻译:
我有两个像这样组织的序列化程序:
class OuterSerializer():
inner_obj = InnerSerializer(many=True, required=False)
其他字段 ......
class InnerSerializer():
field_1 = CharField()
field_2 = CharField()
现在我的用例是部分更新外部序列化程序的模型。我是如何做的:
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)
问题是这个部分标志不会传递到InnerSerializer。例如,如果我的请求正文如下所示,我希望它能工作:
{"inner_obj":
{
"field_1" : "abc"
}
}
目前,对于这个请求,我得到一个400错误,说这个字段是必需的。
我尝试过:
1. 通过在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')
但是这不会传递到内部序列化程序。
英文:
I have two serializers organised like this:
class OuterSerializer():
inner_obj = InnerSerializer(many=True, required=False)
other fields ......
class InnerSerializer():
field_1 = CharField()
field_2 = CharField()
Now my use case is to partial update the outer serializer's model. How I'm doing that is:
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)
The issue is this partial flag does not get passed down to the InnerSerializer.
For example if my request body looks like below, I want it to work:
{"inner_obj":
{
"field_1" : "abc"
}
}
Currently I get a 400 error for this saying the field is required.
What I've tried :
- Setting the partial variable within the OuterSerializer in the init method by modifying it as such
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# We pass the "current serializer" context to the "nested one"
self.fields['inner_obj'].context.update(self.context)
self.fields['inner_obj'].partial = kwargs.get('partial')
However this doesn't travel down.
答案1
得分: 1
尝试修改InnerSerializer
,使其能够接受partial
参数并将其传递给其父类,如下所示:
class InnerSerializer(serializers.Serializer):
field_1 = CharField()
field_2 = CharField()
def __init__(self, *args, **kwargs):
self.partial = kwargs.pop('partial', False)
super().__init__(*args, **kwargs)
class OuterSerializer(serializers.Serializer):
inner_obj = InnerSerializer(many=True, required=False)
其他字段 ......
def __init__(self, *args, **kwargs):
partial = kwargs.get('partial')
super().__init__(*args, **kwargs)
self.fields['inner_obj'].child.partial = partial
另一个可能的解决方案。
您还可以在InnerSerializer
中重写to_internal_value()
方法,以使其接受部分更新,如下所示:
class InnerSerializer(serializers.Serializer):
field_1 = CharField()
field_2 = CharField()
def to_internal_value(self, data):
if self.partial:
return {field: data.get(field, getattr(self.instance, field)) for field in data}
return super().to_internal_value(data)
class OuterSerializer(serializers.Serializer):
inner_obj = InnerSerializer(many=True, required=False)
其他字段 ......
编辑:
对于错误:
> KeyError: "Got KeyError when attempting to get a value for field field_2on serializer
InnerSerializer`.
您遇到的错误消息表明序列化器正在尝试从数据中访问field_2
的值,但它不存在。
目前,为了解决错误,您应该重写InnerSerializer
中的to_representation()
方法,只包括存在的字段,如下所示:
class InnerSerializer(serializers.Serializer):
field_1 = CharField()
field_2 = CharField()
def to_representation(self, instance):
data = super().to_representation(instance)
return {field: value for field, value in data.items() if value is not None}
英文:
Try to modify the InnerSerializer
so that it could accept the partial
argument and pass it to its parent, like following:
class InnerSerializer(serializers.Serializer):
field_1 = CharField()
field_2 = CharField()
def __init__(self, *args, **kwargs):
self.partial = kwargs.pop('partial', False)
super().__init__(*args, **kwargs)
class OuterSerializer(serializers.Serializer):
inner_obj = InnerSerializer(many=True, required=False)
other fields ......
def __init__(self, *args, **kwargs):
partial = kwargs.get('partial')
super().__init__(*args, **kwargs)
self.fields['inner_obj'].child.partial = partial
Another possible solution.
You can also override the to_internal_value()
method in the InnerSerializer
to make it accept partial
updates so:
class InnerSerializer(serializers.Serializer):
field_1 = CharField()
field_2 = CharField()
def to_internal_value(self, data):
if self.partial:
return {field: data.get(field, getattr(self.instance, field)) for field in data}
return super().to_internal_value(data)
class OuterSerializer(serializers.Serializer):
inner_obj = InnerSerializer(many=True, required=False)
other fields ......
Edit:
For the error:
> KeyError: "Got KeyError when attempting to get a value for field field_2on serializer
InnerSerializer`.
The error message you're encountering suggests that the serializer is trying to access the value for field_2
from the data, but it's not present.
Currently to solve the error, you should override the to_representation()
method in the InnerSerializer
to only include the fields that are present so:
class InnerSerializer(serializers.Serializer):
field_1 = CharField()
field_2 = CharField()
def to_representation(self, instance):
data = super().to_representation(instance)
return {field: value for field, value in data.items() if value is not None}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论