Как сериализовать несколько объектов из модели Django и добавить динамически вычисляемые данные в выводимый JSON для каждого объекта?

Я переношу PHP-код Laravel на Python Django/Django Rest Framework.

Моя конечная точка будет выводить JSON.

Мне нужно вывести много объектов, но мне нужно добавить дополнительные вычисляемые значения для каждого объекта. Как я могу этого добиться?

Например, моя модель:

from django.db import models
from rest_framework.serializers import ModelSerializer

class MyObject(models.Model):
    name = models.CharField(max_length=255)
    score = models.IntegerField()

class MyObjectSerializer(ModelSerializer):
    class Meta:
        model = MyObject
        fields = ( 'name', 'score' )

Я получаю набор запросов с помощью MyObject.objects.all() (или с помощью фильтра). Для каждого объекта MyObject в моем наборе запросов я вычисляю дополнительное значение, называемое 'stats', которое я хочу вывести в моем JSON выходе.

Например, если у меня есть 2 объекта MyObject(name='foo',score='1') и MyObject(name='bar',score='2'), я вычислю значение статистики для каждого объекта.

И мой вывод JSON должен быть таким :

{
   { 
       'name': 'foo',
       'score': 1,
       'stats': 1.2
   },
   { 
       'name': 'bar',
       'score': 2,
       'stats': 1.3
   },
}

Какой самый чистый способ, если таковой имеется, для достижения этой цели?

Я могу сделать цикл для каждого MyObject, сериализовать каждый MyObject по очереди с помощью сериализатора, создать и обновить словарь для этого объекта, добавив ключ 'stats'. Меня беспокоит производительность.

Что если я вычисляю значение статистики только для некоторых объектов, смешивая 2 вида вывода?

Вы можете использовать SerializerMethodField:

class MyObjectSerializer(ModelSerializer):
    stat = SerializerMethodField()

    class Meta:
        model = MyObject
        fields = ( 'name', 'score', 'stat' )

    def get_stat(self, obj):
        # obj is the model instance (it passes only one even if many=True)
        # do calculations with obj and return the value
        return None

Если производительность является проблемой, когда поле stat использует модели связанных/иностранных ключей, вы можете использовать аннотации или select_related/prefetch_related. Использование аннотаций более эффективно, но может оказаться сложным для создания в зависимости от требований.

Если есть возможность аннотации, можно использовать другие поля сериализатора, например:

class MyObjectSerializer(ModelSerializer):
    stat = FloatField(read_only=True)

    class Meta:
        model = MyObject
        fields = ( 'name', 'score', 'stat' )

Помимо того, что написал @kyell, вы также можете создать свойство в моделях с помощью декоратора @property и вернуть вычисленные данные, это свойство всегда только для чтения.

Вернуться на верх