Home > Back-end >  How to serialize multiples objects from a Django model and add dynamically computed data in outputed
How to serialize multiples objects from a Django model and add dynamically computed data in outputed

Time:04-22

I'm porting a Laravel PHP code to Python Django/Django Rest Framework.

My endpoint will output JSON.

I need to output many objects, but I need to add extra computed values for each object. How can I achieve this ?

For example, my model is :

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' )

I retrieve a queryset with MyObject.objects.all() (or with filter). For each MyObject in my queryset, I compute an extra value, called 'stats', that I want to output in my JSON output.

For example, if I have 2 objects MyObject(name='foo',score='1') and MyObject(name='bar',score='2'), I will compute a stats value for each object.

And my JSON output should be like :

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

What is the cleanest way , if any to achieve this ?

I can have a loop for each MyObject, serialize each MyObject, one by one with a serializer, and create and update dictionary for this object adding 'stats' key. I'm afaid about performance.

What if I compute stats value only for some objects, mixing 2 kind of output ?

CodePudding user response:

You can use 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

If performance is a concern where stat field uses related/foreign key models, you can either use annotations or select_related/prefetch_related. Using annotation is more efficient but can get difficult to create depending on the requirement.

If it's possible to annotate you can use other serializer fields like:

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

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

CodePudding user response:

Apart from what @kyell wrote, you can also create a property in models using @property decorator and return your calculated data, this property is always read only.

  • Related