Django aggregation: сумма, тогда средняя

Использование django ORM annotate() и/или aggregate(): я хочу подвести итоги на основе одного поля категории, а затем усреднить по значениям категории за дату. Я попытался сделать это, используя два оператора annotate(), но получив FieldError.

Я делаю это:

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

Что выводит объект ValuesQuerySet с такими вещами (так что сумма для каждого значения категории):

[{'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}, ...
]

Затем я хочу усреднить поле sum_for_field для каждой даты, чтобы вывести что-то вроде:

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

Я попытался сделать это:

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

Но я получил этот FieldError:

FieldError: FieldError: Cannot compute Avg('sum_for_field'): 'sum_for_field' is an aggregate

Ответ 1

Совокупная аннотация по группам из многих аннотаций агрегатов по группам обычно является сложным вопросом, но Avg из Sum является специальным гораздо проще. p >

Выражение Avg('sum_for_field') может быть оценено как Sum('sum_for_field') / Count('category', distinct=True), которое может быть оценено с помощью выражений Aggregate(). Sum('sum_for_field') равно Sum('amount').

Решение: (Ожидаемые имена: модель Data имеет поля date, category, amount.)

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

(Я убежден, что очень похожие вопросы были бы без решения текущего Django 1.11, даже с классом Subquery, без использования странного метода extra() и без сырого SQL)

Ответ 2

Я не сделал глубокого погружения, но я подозреваю, что, когда вы используете values() без аннотации, значения sum_for_field объединяются с теми, которые имеют один и тот же date. Я думаю, вам нужно оценить аннотацию сразу после использования values(). Возможно, что-то вроде ниже решит вашу проблему:

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