У меня есть модель, для которой я хочу выполнить группирование по двум значениям и рассчитать проценты каждого значения для внешней группировки.
В настоящее время я просто делаю запрос, чтобы получить все строки, поместить их в кадр данных pandas и выполнить что-то похожее на ответ здесь . Хотя это работает, я уверен, что было бы более эффективно, если бы я мог заставить запрос возвращать информацию, которая мне нужна напрямую.
В настоящее время я работаю Django 2.0.5
с внутренней базой данных на PostgreSQL 9.6.8
Я думаю, что оконные функции могли бы быть решением, как указано здесь , но я не могу создать успешную комбинацию annotate
и values
, чтобы получить желаемый результат.
Другое возможное решение может быть rollup
введено в PostgreSQL 9.5
, если я смогу найти способ получить итоговую строку в виде набора дополнительных столбцов для каждой строки? Но я также думаю, что это еще не поддерживается Джанго.
Модель:
class ModelA(models.Model):
grouper1 = models.CharField()
grouper2 = models.CharField()
metric1 = models.IntegerField()
Все строки:
grouper1 | grouper2 | metric1
---------+----------+---------
A | C | 2
A | C | 2
A | C | 2
A | D | 4
A | D | 4
A | D | 4
B | C | 5
B | C | 5
B | C | 5
B | D | 6
B | D | 4
B | D | 5
Желаемый вывод:
grouper1 | grouper2 | sum(metric1) | Percentage
---------+----------+--------------+-----------
A | C | 6 | 40
A | D | 12 | 60
B | C | 15 | 50
B | D | 15 | 50
Я приблизился к тому, что ожидал с
ModelA.objects.all(
).values(
'grouper1',
'grouper2'
).annotate(
SumMetric1=Window(expression=Sum('metric1'), partition_by=[F('grouper1'), F('grouper2')]),
GroupSumMetric1=Window(expression=Sum('metric1'), partition_by=[F('grouper1')])
)
Однако это возвращает строку для каждой исходной строки в базе данных следующим образом:
grouper1 | grouper2 | sum(metric1) | Percentage
---------+----------+--------------+-----------
A | C | 6 | 40
A | C | 6 | 40
A | C | 6 | 40
A | D | 12 | 60
A | D | 12 | 60
A | D | 12 | 60
B | C | 15 | 50
B | C | 15 | 50
B | C | 15 | 50
B | C | 15 | 50
B | C | 15 | 50
B | D | 15 | 50