将 `partial=True` 传递到 DRF 中的嵌套序列化器

huangapple go评论106阅读模式
英文:

Passing partial=True down to nested serializer in DRF

问题

以下是您要求的内容的翻译:

  1. 我有两个像这样组织的序列化程序
  2. class OuterSerializer():
  3. inner_obj = InnerSerializer(many=True, required=False)
  4. 其他字段 ......
  5. class InnerSerializer():
  6. field_1 = CharField()
  7. field_2 = CharField()
  8. 现在我的用例是部分更新外部序列化程序的模型我是如何做的
  9. def partial_update(self, request, *args, **kwargs):
  10. serializer = OuterSerializer(data=request.data, context={'request': self.request}, partial=True)
  11. serializer.is_valid(raise_exception=True)
  12. data = serializer.data
  13. outerobj = self.service_layer.update(kwargs['pk'], data, request.user)
  14. response_serializer = OpportunitySerializer(instance=outerobj, context={'request': self.request})
  15. return Response(response_serializer.data, HTTPStatus.OK)
  16. 问题是这个部分标志不会传递到InnerSerializer例如如果我的请求正文如下所示我希望它能工作
  17. {"inner_obj":
  18. {
  19. "field_1" : "abc"
  20. }
  21. }
  22. 目前对于这个请求我得到一个400错误说这个字段是必需的
  23. 我尝试过
  24. 1. 通过在OuterSerializerinit方法中修改它来设置partial变量
  25. def __init__(self, *args, **kwargs):
  26. super().__init__(*args, **kwargs)
  27. # 我们将“当前序列化程序”的上下文传递给“嵌套序列化程序”
  28. self.fields['inner_obj'].context.update(self.context)
  29. self.fields['inner_obj'].partial = kwargs.get('partial')
  30. 但是这不会传递到内部序列化程序
英文:

I have two serializers organised like this:

  1. class OuterSerializer():
  2. inner_obj = InnerSerializer(many=True, required=False)
  3. other fields ......
  1. class InnerSerializer():
  2. field_1 = CharField()
  3. field_2 = CharField()

Now my use case is to partial update the outer serializer's model. How I'm doing that is:

  1. def partial_update(self, request, *args, **kwargs):
  2. serializer = OuterSerializer(data=request.data, context={'request': self.request}, partial=True)
  3. serializer.is_valid(raise_exception=True)
  4. data = serializer.data
  5. outerobj = self.service_layer.update(kwargs['pk'], data, request.user)
  6. response_serializer = OpportunitySerializer(instance=outerobj, context={'request': self.request})
  7. 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:

  1. {"inner_obj":
  2. {
  3. "field_1" : "abc"
  4. }
  5. }

Currently I get a 400 error for this saying the field is required.

What I've tried :

  1. Setting the partial variable within the OuterSerializer in the init method by modifying it as such
  1. def __init__(self, *args, **kwargs):
  2. super().__init__(*args, **kwargs)
  3. # We pass the "current serializer" context to the "nested one"
  4. self.fields['inner_obj'].context.update(self.context)
  5. self.fields['inner_obj'].partial = kwargs.get('partial')

However this doesn't travel down.

答案1

得分: 1

尝试修改InnerSerializer,使其能够接受partial参数并将其传递给其父类,如下所示:

  1. class InnerSerializer(serializers.Serializer):
  2. field_1 = CharField()
  3. field_2 = CharField()
  4. def __init__(self, *args, **kwargs):
  5. self.partial = kwargs.pop('partial', False)
  6. super().__init__(*args, **kwargs)
  7. class OuterSerializer(serializers.Serializer):
  8. inner_obj = InnerSerializer(many=True, required=False)
  9. 其他字段 ......
  10. def __init__(self, *args, **kwargs):
  11. partial = kwargs.get('partial')
  12. super().__init__(*args, **kwargs)
  13. self.fields['inner_obj'].child.partial = partial

另一个可能的解决方案。

您还可以在InnerSerializer中重写to_internal_value()方法,以使其接受部分更新,如下所示:

  1. class InnerSerializer(serializers.Serializer):
  2. field_1 = CharField()
  3. field_2 = CharField()
  4. def to_internal_value(self, data):
  5. if self.partial:
  6. return {field: data.get(field, getattr(self.instance, field)) for field in data}
  7. return super().to_internal_value(data)
  8. class OuterSerializer(serializers.Serializer):
  9. inner_obj = InnerSerializer(many=True, required=False)
  10. 其他字段 ......

编辑:

对于错误:

> KeyError: "Got KeyError when attempting to get a value for field field_2on serializerInnerSerializer`.

您遇到的错误消息表明序列化器正在尝试从数据中访问field_2的值,但它不存在。

目前,为了解决错误,您应该重写InnerSerializer中的to_representation()方法,只包括存在的字段,如下所示:

  1. class InnerSerializer(serializers.Serializer):
  2. field_1 = CharField()
  3. field_2 = CharField()
  4. def to_representation(self, instance):
  5. data = super().to_representation(instance)
  6. 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:

  1. class InnerSerializer(serializers.Serializer):
  2. field_1 = CharField()
  3. field_2 = CharField()
  4. def __init__(self, *args, **kwargs):
  5. self.partial = kwargs.pop('partial', False)
  6. super().__init__(*args, **kwargs)
  7. class OuterSerializer(serializers.Serializer):
  8. inner_obj = InnerSerializer(many=True, required=False)
  9. other fields ......
  10. def __init__(self, *args, **kwargs):
  11. partial = kwargs.get('partial')
  12. super().__init__(*args, **kwargs)
  13. 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:

  1. class InnerSerializer(serializers.Serializer):
  2. field_1 = CharField()
  3. field_2 = CharField()
  4. def to_internal_value(self, data):
  5. if self.partial:
  6. return {field: data.get(field, getattr(self.instance, field)) for field in data}
  7. return super().to_internal_value(data)
  8. class OuterSerializer(serializers.Serializer):
  9. inner_obj = InnerSerializer(many=True, required=False)
  10. other fields ......

Edit:

For the error:

> KeyError: "Got KeyError when attempting to get a value for field field_2on serializerInnerSerializer`.

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:

  1. class InnerSerializer(serializers.Serializer):
  2. field_1 = CharField()
  3. field_2 = CharField()
  4. def to_representation(self, instance):
  5. data = super().to_representation(instance)
  6. return {field: value for field, value in data.items() if value is not None}

huangapple
  • 本文由 发表于 2023年2月9日 03:01:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75390544.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定