使用相关模型汇总查询,而不仅仅是相关的ID值

时间:2015-05-08 00:18:10

标签: django orm model aggregate-functions

说我有三个型号:

from django.db import models    

class X(models.Model):
    y = models.ForeignKey(Y, on_delete=models.PROTECT)
    z = models.ForeignKey(Z, on_delete=models.PROTECT)
    a = models.DecimalField(...)
    b = models.DecimalField(...)
    ...some fields...

class Y(models.Model):
   ...some fields...

class Z(models.Model):
   ...some fields...

我想使用ORM使用X模型进行聚合查询,但我不想按X.id分组(我想按Xa分组)我希望生成的对象具有Y和Z相关模型预先填充(以避免重复查询相关数据)。

据我所知,Django的聚合查询仅允许您按模型的ID进行分组(在我看来有点无用),或者按其他字段分组,然后将结果折叠为单个记录/对象。 / p>

没有中间地带允许您按照模型ID以外的字段进行分组,而不会将结果折叠为单个记录/对象。

我意识到这很可能是因为这个中间地带不适合模型的概念(因为如果将多个模型记录组合在一起,它们实际上不再是模型实例),但它会很好能够利用ORM的力量并实现这个中间地带。

目前我不得不回避ORM并推出我自己的自定义模型实现并使用原始查询,但它有点hacky我希望发布Django 1.8并且它的新查询功能我可以回到ORM,但似乎并非如此。

我能得到的最接近的是:

X.objects.all().values('a', 'y', 'z').annotate(temp=Sum('b'))

...转换为此SQL:

SELECT app_x.a, app_x.y_id, app_x.z_id, SUM(app_x.b) AS temp
FROM app_x LEFT OUTER JOIN app_y ON (app_x.y_id = app_y.id)
GROUP BY app_x.a, app_x.y_id, app_x.z_id

我想从ORM获得的SQL是这样的:

SELECT app_x.a, app_y.*, app_z.*, SUM(app_x.b) AS temp
FROM app_x LEFT OUTER JOIN app_y ON (app_x.y_id = app_y.id)
   LEFT OUTER JOIN app_z ON (app_x.z_id = app_z.id)
GROUP BY app_x.a, app_y.*, app_z.*

...所以我不仅仅获取相关的ID,而是可以立即使用并避免将来查询的完整模型实例。

ORM是否允许这样做?

我能看到的唯一解决方案是在.values()调用中手动定义相关模型中的所有字段,但这不会返回查询集,并且必须手动列出所有必要的相关内容有点乏味字段(而不是只执行.select_related()调用)。

修改1

如果.values()调用返回实际的相关模型对象而不仅仅是它们的ID值,这将很容易。

即。我认为这样的查询:

X.objects.all.values('y')

...应返回包含Y对象的字典列表,而不是Y ID。

这样的查询:

X.objects.all.values('y_id')

...应该返回包含ID的词典列表,因为这是你要求的。

有人同意我的意见吗?

1 个答案:

答案 0 :(得分:1)

X.objects.annotate(temp=Sum('b')).select_related('y','z')是否适合您?

select_related docs

编辑:刚刚看到你在问题中排除了这一点。我没试过,但values_list()可能会返回外键字段的模型实例吗?如果没有,并且您使用values()的原因是模型X上的许多不需要的字段,可以考虑使用defer/only