我有一张看起来像这样的桌子
date car_crashes city
01.01 1 Washington
01.02 4 Washington
01.03 0 Washington
01.04 2 Washington
01.05 0 Washington
01.06 3 Washington
01.07 4 Washington
01.08 1 Washington
01.01 0 Detroit
01.02 2 Detroit
01.03 4 Detroit
01.04 2 Detroit
01.05 0 Detroit
01.06 3 Detroit
01.07 1 Detroit
我想知道整个国家每天发生多少起车祸,我可以这样做:
Model.values("date") \
.annotate(car_crashes=Sum('car_crashes')) \
.values("date", "car_crashes")
现在,让我们假设我有一个像这样的数组:
weights = [
{
"city": "Washington",
"weight": 1,
},
{
"city": "Detroit",
"weight": 2,
}
]
这意味着底特律的车祸应该与华盛顿相乘之前应乘以2。
可以这样做:
from django.db.models import IntegerField
when_list = [When(city=w['city'], then=w['weight']) for w in weights]
case_params = {'default': 1, 'output_field': IntegerField()}
Model.objects.values('date') \
.annotate(
weighted_car_crashes=Sum(
F('car_crashes') * Case(*when_list, **case_params)
))
但是,这会生成非常慢的SQL代码,尤其是在引入更多属性和更大数组的情况下。
另一种更快但仍然不理想的解决方案是使用熊猫:
aggregated = false
for weight in weights:
ag = Model.filter(city=w[‘city’]).values("date") \
.annotate(car_crashes=Sum('car_crashes') * w[‘weight’]) \
.values("date", "car_crashes")
if aggregated is False:
aggregated = ag
else:
aggregated = aggregated.union(ag)
aggregated = pd.DataFrame(aggregated)
if len(weights) > 1:
aggregated = aggregated.groupby("date", as_index=False).sum(level=[1])
这更快,但仍不如在调用大熊猫之前我将aggregated.query
字符串和
用几行SQL封装它。
SELECT "date", sum("car_crashes") FROM (
// String from Python
str(aggregated.query)
) as "foo" GROUP BY "date"
当粘贴到我的数据库SQL中时,这非常完美。我可以在Python / Django中使用.raw()
来做到这一点,但是文档说要在使用.raw()
之前先询问一下,因为大多数内容都可以通过ORM完成。
但是,我不知道如何。一旦我在2个查询集上调用.union()
,就无法进一步汇总。
aggregated.union(ag).annotate(cc=Sum('car_crashes'))
给予
无法计算Sum('car_crashes'):'car_crashes'是一个聚合
这可能与Django ORM有关还是应该使用.raw()?