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
для различных поддерживаемых СУБД.