Why won't serialize capture annotate fields?

3.5k Views Asked by At

I had no idea adding data to a queryset would be so hard. It's like, if it didn't come directly from the db then it might as well not exist. Even when I annotate, the new fields are 2nd class citizens and aren't always available.

Why won't serialize capture my annotate fields?

Model

class Parc(models.Model):
    # Regular Django fields corresponding to the attributes in the
    # world borders shapefile.
    prop_id = models.IntegerField(unique=True)  # OBJECTID: Integer (10.0)
    shp_id = models.IntegerField()

    # GeoDjango-specific: a geometry field (MultiPolygonField)
    mpoly = models.MultiPolygonField(srid=2277)
    sale_price = models.DecimalField(max_digits=8, decimal_places=2, null=True)
    floorplan_area = models.DecimalField(max_digits=8, decimal_places=2, null=True)
    price_per_area = models.DecimalField(max_digits=8, decimal_places=2, null=True)
    nbhd = models.CharField(max_length=200, null=True)
    # Returns the string representation of the model.
    def __str__(self):              # __unicode__ on Python 2
        return str(self.shp_id)

Query:

parcels = Parc.objects\
    .filter(prop_id__in=attrList)\
    .order_by('prop_id') \
    .annotate(avg_price=Avg('sale_price'),
              perc_90_price=RawAnnotation('percentile_disc(%s) WITHIN GROUP (ORDER BY sale_price)', (0.9,)),
              )
geojson = serialize('geojson', parcels)  

When I print geojson it has no key/values for avg_price or perc_90_price. At this point, I'm leaning towards creating a dummy field and then populating it with the my customer calculations after I retrieve the queryset but I'm open to ideas.

Helper class

class RawAnnotation(RawSQL):
"""
RawSQL also aggregates the SQL to the `group by` clause which defeats the purpose of adding it to an Annotation.
"""
def get_group_by_cols(self):
    return []
1

There are 1 best solutions below

2
On

I use annotations with Django Rest Framework and the Serializers in that library.

In particular, the serializer method allows you to access the query set. You can do something like this.

class SomeSerializer(serializers.ModelSerializer):
  avg_price = serializers.SerializerMethodField()

  def get_avg_price(self, obj):
    try:
        return obj.avg_price
    except:
        return None

As mentioned by Carl Kroeger Ihl, you can also use:

class SomeSerializer(serializers.ModelSerializer): 
   avg_price = serializers.IntegerField(allow_null=True)

http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield