У меня есть JSONField
в моей модели, в которой хранятся некоторые данные конфигурации. Я хочу получить доступ к этому полю (как для чтения, так и для записи) с возможностью частичного обновления внутренних полей и их значений.
Для примера пусть модель называется MyModel
, а JSONField
называется config
:
class MyModel(models.Model):
config = JSONField(default=dict())
...
Я создал отдельный ViewSet
для доступа к информации, хранящейся в поле config
. Предположим, что модель user
имеет отношение ForeignKey
к MyModel
. Упрощенная версия этого ViewSet
:
class ConfigurationFieldViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):
serializer_class = MyModelConfigurationSerializer
def get_object(self):
return self.request.user.my_model
Данные, хранящиеся в config
, имеют определенную структуру с несколькими возможными внутренними объектами:
{
"C1": {"counter": 42, "active": false},
"C2": {"counter": 13, "active": true}
}
Чтобы получить доступ и правильно сериализовать экземпляр MyModel
на всех уровнях вложенности, я создал сериализаторы для каждого уровня поля. Чтобы получить доступ к полю config
в самом MyModel
, я использую этот сериализатор:
class MyModelConfigurationSerializer(serializers.ModelSerializer):
configuration = ConfigurationFieldSerializer(required=True)
class Meta:
model = MyModel
fields = ('configuration',)
Для доступа и сериализации первого уровня поля configuration
есть второй сериализатор:
class ConfigurationFieldSerializer(serializers.Serializer):
C1 = BaseConfigurationSerializer(required=True)
C2 = BaseConfigurationSerializer(required=True)
Наконец, для доступа к внутренней структуре каждого поля C1
и C2
есть третий сериализатор:
class BaseConfigurationSerializer(serializers.Serializer):
counter = serializers.IntegerField(
required=False,
help_text=_('Some integer field help text')
)
active = serializers.BooleanField(
required=False,
help_text=_('Some boolean field description')
)
Приведенный выше код отлично работает для чтения данных, хранящихся в поле config
, и правильно сериализует его внутренние объекты. Проблема возникает, когда я пытаюсь выполнить PUT
в этом поле.
Если я переопределяю метод update
на уровне MyModelConfigurationSerializer
, то сериализаторы проверяют данные, которые я отправляю, но в виде фрагмента, и я могу сохранить их все сразу. Если я пытаюсь отправить какое-то внутреннее поле, я все равно правильно получаю ошибки проверки внутренними сериализаторами.
def update(self, instance, validated_data):
instance.configuration = validated_data.get(
'configuration', instance.configuration
)
instance.save()
return instance
Чего я не могу сделать, так это вызвать методы update
внутренних сериализаторов (в данном случае ConfigurationFieldSerializer
и BaseConfigurationSerializer
): если я реализую их методы update
, они просто не будут вызываться.
Согласно документации DRF вложенные представления с возможностью записи возможны, и соответствующие методы update
или create
должны вызываться всякий раз, когда update
вызывается в сериализаторе верхнего уровня.
PATCH
вместоPUT
- person ivissani   schedule 16.04.2019update
- person Stan Redoute   schedule 16.04.2019create()
иupdate()
, если вы хотите это сделать. Я комментировал проверку. - person ivissani   schedule 16.04.2019update()
в сериализаторе верхнего уровня, который обрабатывает обновление вложенных объектов. - person ivissani   schedule 16.04.2019