[Fixed]-Django aggregation: sum then average


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)


I haven’t done a deep dive, but I suspect that when you use values() without an annotation, sum_for_field values are being merged with ones that share the same date. I think you need to evaluate the annotation right after you use a values() clause. Maybe something like below will resolve your issue:

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


Leave a comment