title: Aggregate (and other annotated) fields in Django Rest Framework serializers
body: <p>I am trying to figure out the best way to add annotated fields, such as any aggregated (calculated) fields to DRF (Model)Serializers. My use case is simply a situation where an endpoint returns fields that are NOT stored in a database but calculated from a database.</p>
  
  <p>Let's look at the following example:</p>
  
  <p>models.py</p>
  
  <pre><code>class IceCreamCompany(models.Model):
      name = models.CharField(primary_key = True, max_length = 255)
  
  class IceCreamTruck(models.Model):
      company = models.ForeignKey('IceCreamCompany', related_name='trucks')
      capacity = models.IntegerField()
  </code></pre>
  
  <p>serializers.py</p>
  
  <pre><code>class IceCreamCompanySerializer(serializers.ModelSerializer):
      class Meta:
          model = IceCreamCompany
  </code></pre>
  
  <p>desired JSON output:</p>
  
  <pre><code>[
  
      {
          "name": "Pete's Ice Cream",
          "total_trucks": 20,
          "total_capacity": 4000
      },
      ...
  ]
  </code></pre>
  
  <p>I have a couple solutions that work, but each have some issues.</p>
  
  <p><strong>Option 1: add getters to model and use SerializerMethodFields</strong></p>
  
  <p>models.py</p>
  
  <pre><code>class IceCreamCompany(models.Model):
      name = models.CharField(primary_key=True, max_length=255)
  
      def get_total_trucks(self):
          return self.trucks.count()
  
      def get_total_capacity(self):
          return self.trucks.aggregate(Sum('capacity'))['capacity__sum']
  </code></pre>
  
  <p>serializers.py</p>
  
  <pre><code>class IceCreamCompanySerializer(serializers.ModelSerializer):
  
      def get_total_trucks(self, obj):
          return obj.get_total_trucks
  
      def get_total_capacity(self, obj):
          return obj.get_total_capacity
  
      total_trucks = SerializerMethodField()
      total_capacity = SerializerMethodField()
  
      class Meta:
          model = IceCreamCompany
          fields = ('name', 'total_trucks', 'total_capacity')
  </code></pre>
  
  <p>The above code can perhaps be refactored a bit, but it won't change the fact that this option will perform 2 extra SQL queries <em>per IceCreamCompany</em> which is not very efficient.</p>
  
  <p><strong>Option 2: annotate in ViewSet.get_queryset</strong></p>
  
  <p>models.py as originally described.</p>
  
  <p>views.py</p>
  
  <pre><code>class IceCreamCompanyViewSet(viewsets.ModelViewSet):
      queryset = IceCreamCompany.objects.all()
      serializer_class = IceCreamCompanySerializer
  
      def get_queryset(self):
          return IceCreamCompany.objects.annotate(
              total_trucks = Count('trucks'),
              total_capacity = Sum('trucks__capacity')
          )
  </code></pre>
  
  <p>This will get the aggregated fields in a single SQL query but I'm not sure how I would add them to the Serializer as DRF doesn't magically know that I've annotated these fields in the QuerySet. If I add total_trucks and total_capacity to the serializer, it will throw an error about these fields not being present on the Model. </p>
  
  <p>Option 2 can be made work without a serializer by using a <a href="http://www.django-rest-framework.org/api-guide/views/">View</a> but if the model contains a lot of fields, and only some are required to be in the JSON, it would be a somewhat ugly hack to build the endpoint without a serializer.</p>