Home > OS >  How to add aggregate values in Django Rest Framework ModelViewSets
How to add aggregate values in Django Rest Framework ModelViewSets

Time:10-21

In my DRF app I have the following model, serializer and view.

models.py

class Log(models.Model):
    plant = models.ForeignKey(Plant, on_delete=models.CASCADE)
    date_time = models.DateTimeField()
    water_consumption = models.PositiveSmallIntegerField()
    elec_consumption = models.PositiveSmallIntegerField()

serializers.py

class ConsumptionSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Log
        fields = ("water_consumption", "elec_consumption")

views.py

class ConsumptionViewSet(viewsets.ModelViewSet):
    
    permission_classes = [permissions.IsAuthenticated, ]
    serializer_class = ConsumptionSerializer

    def get_queryset(self):
        # Get params from url
        start_date = self.request.query_params.get('start_date')
        end_date = self.request.query_params.get('end_date')
        # Make sure params are not null
        if start_date is not None and end_date is not None:
            queryset = queryset.filter(date_time__range=[start_date, end_date])
            return queryset
        else:
            raise ValidationError({"ERROR": ["No params found in url"]})
            

This works and it outputs something like this in JSON:

[
    {
        "water_consumption": 1,
        "electrical_consumption": 1
    },
    {
        "water_consumption": 1,
        "electrical_consumption": 1
    },
    {
        "water_consumption": 1,
        "electrical_consumption": 1
    },
]

What I would like to achieve is to receive some aggregated data alongside those data, like this:

{
    "total_water_consumption": 3,
    "total_elec_consumption": 3,
    "detailed_logs": [{
        "water_consumption": 1,
        "electrical_consumption": 1
    },
    {
        "water_consumption": 1,
        "electrical_consumption": 1
    },
    {
        "water_consumption": 1,
        "electrical_consumption": 1
    }]
}

How should I customise the queryset to have the total values added?

Thank you in advance.

CodePudding user response:

You can do it with SerializerMethodField in your serializer file

Docs in : https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

And you can access request in serializer as context:

from django.db.models import Sum


class ConsumptionSerializer(serializers.ModelSerializer):
    total_water_consumption = serializers.SerializerMethodField()
    total_elec_consumption = serializers.SerializerMethodField()
    
    class Meta:
        model = Log
        fields = ("water_consumption", "elec_consumption")

    def get_total_water_consumption(self, obj):
        request = self.context['request']
        query_params = request.query_params.get(...)
        return Log.objects.filter(...).aggregate(Sum('water_consumption')).get('water_consumption__sum')

    def get_total_elec_consumption(self, obj):
        request = self.context['request']
        query_params = request.query_params.get(...)
        return Log.objects.filter(...).aggregate(Sum('elec_consumption')).get('elec_consumption__sum')
  • Related