I've got a Django model containing various database model fields. One of the manager's querysets retrieves various aggregations via some annotate calls. Some of those annotations are custom made and retrieve float values from the database. Those annotations are not part of the model's fields. However, when the queryset is created, those floats turn out to be integers in the model, I guess because the there's not a model field to bound them to a float or decimal data type.
Here's some code to demostrate what I mean:
The custom aggregate classes. Note the database casts the result to a float:
class SqlCTR(aggregates.Sum):
is_ordinal = True
sql_function = 'SUM'
sql_template= "CASE WHEN sum(campaignmanager_adstats.impressions) > 0 THEN sum(campaignmanager_adstats.clicks)/sum(campaignmanager_adstats.impressions)::float ELSE 0::float END"
class CTR(Sum):
name='CTR'
def add_to_query(self, query, alias, col, source, is_summary):
aggregate = SqlCTR(col, source=source, is_summary=is_summary)
query.aggregates[alias] = aggregate
And here's the queryset:
camps = self.select_related(depth=3).\
annotate( impressions=Sum('ad__adstats__impressions'),\
clicks=Sum('ad__adstats__clicks'),\
ctr=CTR('ad__adstats__clicks'),\
exclude(**campaignExclude).\
filter(**campaignArgs).order_by(sortBy)
The problem is that although the query itself runs ok and returns CTR as floats, sorts it as a float and filters it just fine (if I run the generated sql in Postgres's console), the resulting Queryset translates the value to an integer, resulting in 0s... (Remember CTR is not a model field).
How can I either make sure that the annotated values load in their right datatype to the model? Can I set a non database model field of DecimalField or FloatField which will preserve the type?
Any idea will be highly appreciated!
Thanks
Harel