Передача partial=True во вложенный сериализатор в DRF

У меня есть два сериализатора, организованных следующим образом:

class OuterSerializer():
  inner_obj = InnerSerializer(many=True, required=False)
  other fields ......
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, изменив его таким образом
    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')  

Однако это не распространяется вниз.

Попробуйте изменить 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)
    other fields ......

    def __init__(self, *args, **kwargs):
        partial = kwargs.get('partial')
        super().__init__(*args, **kwargs)
        self.fields['inner_obj'].child.partial = partial

Еще одно возможное решение.

Вы также можете переопределить метод to_internal_value() в InnerSerializer, чтобы заставить его принимать обновления partial так:

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 ......

Редактирование:

Для ошибки:

KeyError: "Получена ошибка KeyError при попытке получить значение для поля field_2on serializerInnerSerializer`.

Сообщение об ошибке, с которым вы столкнулись, предполагает, что сериализатор пытается получить доступ к значению field_2 из данных, но оно отсутствует.

В настоящее время для решения ошибки необходимо переопределить метод to_representation() в InnerSerializer, чтобы включить только те поля, которые присутствуют, таким образом:

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}
Вернуться на верх