Django - Группировка по, разделение по диапазону дат

У меня есть модель:

class MyModel(models.Model):
    store_id = models.TextField()
    day_dt = models.DateField()
    param1 = models.IntegerField()
    param2 = models.IntegerField()

Пример некоторых данных:

store_id | day_dt     | param1 | param2
----------------------------------------
STORE1   | 2021-09-30 | 10     | 30
STORE2   | 2021-09-31 | 20     | 40
....
STORE1   | 2021-10-01 | 4      | 5
STORE1   | 2021-10-02 | 6      | 10
STORE1   | 2021-10-03 | 2      | 5
STORE2   | 2021-10-02 | 3      | 7
STORE2   | 2021-10-03 | 1      | 19
....

Мне нужно разделить данные на группы по store_id и интервалу (day_dt должен быть между 2021-10-01 и 2021-10-04):

STORE1   | 2021-10-01
STORE1   | 2021-10-02
STORE1   | 2021-10-03

и

STORE2   | 2021-10-02
STORE2   | 2021-10-03 

и затем применяем к каждой (из двух) групп агрегацию: Avg('param1') и Avg('param2').

Ожидаемый вывод для примера данных:

store_id | param1_avg | param2_avg
----------------------------------
STORE1   | 6          | 10
STORE2   | 2          | 13

Как я могу сделать эту агрегацию с помощью ORM?

Вы можете реализовать это с помощью:

from django.db.models import Avg

MyModel.objects.filter(
    date_dt__range=('2021-10-01', '2021-10-04')
).values('store_id').annotate(
    param1_avg=Avg('param1'),
    param2_avg=Avg('param2')
).order_by('store_id')

Это вернет QuerySet словарей, которые будут иметь вид:

<QuerySet [
    {'store_id': 'STORE1', param1_avg: 6, param2_avg: 10},
    {'store_id': 'STORE2', param1_avg: 2, param2_avg: 13}
]>

магазины, не имеющие MyModel записей для заданного диапазона дат, не будут иметь объект словаря в результирующем наборе запросов.

Вы можете использовать это решение - это самый простой способ.

Но решение Django - это использование Expression и написание собственных Query Expressions. В этом решении вы создаете выражение типа Hours и используете его в функции annotate, например: .annotate(Hours("day_dt")). Вы должны переопределить функцию as_sql, чтобы написать свой собственный метод SQL или переопределить функции as_sqlite и as_postgresql для различных поддерживаемых СУБД.

Вернуться на верх