Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django aggregation: sum then average

Tags:

python

orm

django

Using django's ORM annotate() and/or aggregate(): I want to sum up based on one category field and then average over the category values per date. I tried to do it using two annotate() statements but got a FieldError.

I'm doing this:

queryset1 = self.data.values('date', 'category').annotate(sum_for_field=Sum('category'))

Which outputs a ValuesQuerySet object with things like (so a sum for each value of category):

[{'category': 'apples', 'date': '2015-10-12', sum_for_field=2000},
 {'category': 'carrots', 'date': '2015-10-12', sum_for_field=5000},
 {'category': 'apples', 'date': '2015-10-13', sum_for_field=3000},
 {'category': 'carrots', 'date': '2015-10-13', sum_for_field=6000}, ...
]

I then want to average the sum_for_field field for each date to output something like:

[ {'date': '2015-10-12', avg_final: 3500},
{'date': '2015-10-13', avg_final: 4500}, ...
]

I tried doing this:

queryset2 = queryset1.values('date', 'sum_for_field')
result = queryset2.annotate(avg_final=Avg('sum_for_field'))

But I got this FieldError:

FieldError: FieldError: Cannot compute Avg('sum_for_field'): 'sum_for_field' is an aggregate
like image 448
user1387717 Avatar asked Jan 20 '16 22:01

user1387717


People also ask

How does Django calculate average?

You can use aggregate and Avg in a django query. This does the average overall, however I need the average of each member if you understand me? Yes! For example Aragorn has 34 wins and 27 losses.

What is difference between annotate and aggregate in Django?

In the Django framework, both annotate and aggregate are responsible for identifying a given value set summary. Among these, annotate identifies the summary from each of the items in the queryset. Whereas in the case of aggregate, the summary is calculated for the entire queryset.

What does aggregate do in Django?

When specifying the field to be aggregated in an aggregate function, Django will allow you to use the same double underscore notation that is used when referring to related fields in filters. Django will then handle any table joins that are required to retrieve and aggregate the related value.


1 Answers

Aggregate annotation by group from many aggregate annotations by group is generally a complicated question, but Avg from Sum is a special much easier case.

Expression Avg('sum_for_field') can be evaluated as Sum('sum_for_field') / Count('category', distinct=True) that can be evaluated by Aggregate() expressions. The Sum('sum_for_field') equals Sum('amount').

Solution: (Expected names: The model is Data that has fields date, category, amount.)

qs = Data.objects.values('date').annotate(
    avg_final=Sum('amount') / Count('category', distinct=True)
)

(I'm convinced that very similar questions would be without any solution by current Django 1.11, even with Subquery class, without using a strange extra() method and without raw SQL)

like image 199
hynekcer Avatar answered Sep 23 '22 02:09

hynekcer