Django REST Framework: добавление дополнительного поля в ModelSerializer

Я хочу сериализовать модель, но хочу включить дополнительное поле, которое требует выполнения некоторых запросов базы данных на экземпляре модели для сериализации:

class FooSerializer(serializers.ModelSerializer):
  my_field = ... # result of some database queries on the input Foo object
  class Meta:
        model = Foo
        fields = ('id', 'name', 'myfield')

Каков правильный способ сделать это? Я вижу, что вы можете передать дополнительный "контекст" в сериализатор, является ли правильным ответом на переход в дополнительное поле в словаре контекста? При таком подходе логика получения нужного поля не будет самодостаточной с определением сериализатора, что идеально, поскольку каждый сериализованный экземпляр понадобится my_field. В другом месте документации документаторов серии DRF говорит "дополнительные поля могут соответствовать любому свойству или вызываемому на модели". Есть лишние поля, о чем я говорю? Должен ли я определить функцию в определении модели Foo, которая возвращает значение my_field, а в сериализаторе я подключаю my_field к этому вызываемому? Как это выглядит?

Заранее благодарим, если вам необходимо, прояснить вопрос.

Ответ 1

Я думаю, что SerializerMethodField - это то, что вы ищете:

class FooSerializer(serializers.ModelSerializer):
  my_field = serializers.SerializerMethodField('is_named_bar')

  def is_named_bar(self, foo):
      return foo.name == "bar" 

  class Meta:
    model = Foo
    fields = ('id', 'name', 'my_field')

http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

Ответ 2

Вы можете изменить свой метод модели на свойство и использовать его в сериализаторе с таким подходом.

class Foo(models.Model):
    . . .
    @property
    def my_field(self):
        return stuff
    . . .

class FooSerializer(ModelSerializer):
    my_field = serializers.ReadOnlyField(source='my_field')

    class Meta:
        model = Foo
        fields = ('my_field',)

Изменить: в последних версиях системы отдыха (я пробовал 3.3.3) вам не нужно менять свойство. Метод модели будет работать нормально.

Ответ 3

Мой ответ на аналогичный вопрос (здесь) может оказаться полезным.

Если у вас есть метод модели, определенный следующим образом:

class MyModel(models.Model):
    ...

    def model_method(self):
        return "some_calculated_result"

Вы можете добавить результат вызова указанного метода к вашему сериализатору следующим образом:

class MyModelSerializer(serializers.ModelSerializer):
    model_method_field = serializers.CharField(source='model_method')

p.s. Поскольку пользовательское поле на самом деле не является полем в вашей модели, вы, как правило, хотите сделать его доступным только для чтения, например:

class Meta:
    model = MyModel
    read_only_fields = (
        'model_method_field',
        )

Ответ 4

В последней версии Django Rest Framework вам необходимо создать метод в вашей модели с именем поля, которое вы хотите добавить. Нет необходимости в @property и source='field' вызывать ошибку.

class Foo(models.Model):
    . . .
    def foo(self):
        return 'stuff'
    . . .

class FooSerializer(ModelSerializer):
    foo = serializers.ReadOnlyField()

    class Meta:
        model = Foo
        fields = ('foo',)