Как сделать поле в Сериализаторе как читабельным, так и записываемым - PullRequest
4 голосов
/ 15 мая 2019

Я пишу сериализатор для моей модели, доступ к которому осуществляется с помощью конечных точек GET, POST и PATCH. У меня есть свойство в моей модели, которое я использую в качестве источника для поля. Однако использование source= в поле сериализатора делает его только готовым.

Если я удалю source="get_field1" из

field1 = serializers.NullBooleanField(source="get_field1")

тогда я могу обновить данные.

Но я ДОЛЖЕН использовать источник, чтобы получить правильное значение поля.

class MyModel(models.Model):
    field1 = NullBooleanField(default=None)

    @property
    get_field1(self):
       data = True
       # ...some logic
       return data

Теперь у меня есть сериализатор, который я использую

    class MyModelSerializer(serializers.ModelSerializer):
        field1 = serializers.NullBooleanField(source="get_field1")
        class Meta:
             model = MyModel
             fields = ('field1')

Теперь в моей конечной точке API я делаю это

    serializer = MyModelSerializer(my_model, data=request.data, partial=True)
    if serializer.is_valid():
        serializer.save() # <- throws error "can't set attribute"

Также хотелось бы отметить, что поле в сериализаторе указывается по имени свойства, а не по имени поля.

Пример: если я сделаю

>> serializer.validated_data

>> 'OrderedDict(['get_field1'], True) # <- shouldn't this by field1 and not get_field1

Ответы [ 2 ]

3 голосов
/ 16 мая 2019

Это можно сделать путем переопределения метода сериализатора __init__().Кроме того, мы должны передать некоторые context данные в сериализатор, чтобы различать запросы GET, POST и PATCH.

class MyModelSerializer(serializers.ModelSerializer):
    <b>field1 = serializers.NullBooleanField()  # remove "source" argument from here

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.context['request'].method == 'GET':
            self.fields['field1'] =serializers.NullBooleanField(source= "get_field1")</b>

    class Meta:
        model = MyModel
        fields = ('field1',)

и при сериализации данных не забудьте передать запрос в виде контекста, как

serializer = MyModelSerializer(my_model, data=request.data, partial=True, <b>context={"request": request}</b>)
2 голосов
/ 16 мая 2019

Ответ @JPG - это хорошо, но я чувствую, что это хакерский способ.

Я бы переопределил to_representation метод Serializer для достижения вашей цели.

Вот что вы можетеdo

class MyModelSerializer(serializers.ModelSerializer):
        field1 = serializers.NullBooleanField() # get rid of source

        def to_representation(self, instance):
             data = super(MyModel, self).to_representation(instance)
             data.update({
                  'field1': instance.get_field1
             })
             return data       

        class Meta:
             model = MyModel
             fields = ('field1')

Таким образом, вы неявно предоставляете источник, и ваше поле становится доступным для записи.Поэтому каждый раз, когда вы получаете, POST или PATCH, вы получите правильное значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...