汇总联合查询的结果,而不使用原始数据

时间:2019-08-19 20:19:21

标签: django django-orm

我有一张看起来像这样的桌子

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()?

0 个答案:

没有答案