Why won't serialize capture annotate fields?
Asked Answered
S

1

7

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 []
Savaii answered 8/9, 2017 at 17:47 Comment(4)
What does the serialize() exactly do?Chemosynthesis
Takes a queryset and turns it into JSON. Specifically, in this case geojson but it ignores the annotate fields. I think i'm going to try and turn the serialized string back into JSON structure, modify it, and then re-serialize.Savaii
https://mcmap.net/q/859794/-django-how-can-you-include-annotated-results-in-a-serialized-queryset seems annotations will not appear while serializing.Chemosynthesis
I ended up turning the serialized string back into a true json object, modifying the properties' subdict, and then re-serializing.Savaii
P
7

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

Perkoff answered 1/8, 2018 at 3:2 Comment(2)
Just tested it and it works, exactly what I needed too.Compte
You could also use avg_price = serializers.IntegerField(allow_null=True) and not need the get_avg_price functionYonah

© 2022 - 2025 — McMap. All rights reserved.