我有一个模型:
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的解决方案是使用表达式并编写自己的查询表达式。在这个解决方案中,创建一个类似Hours
的表达式,并在annotate
函数中使用它,如:.annotate(Hours("day_dt"))
。您应该重写as_sql
函数来编写自定义SQL方法,或者重写as_sqlite
和as_postgresql
函数以支持不同的DBMS。