Как сериализовать несколько объектов из модели 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 и вернуть вычисленные данные, это свойство всегда только для чтения.