说我有三个型号:
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进行分组(在我看来是无用的),或者按照另一个字段进行分组,然后将结果折叠成单个记录/对象 .
没有中间地带允许您按模型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()调用) .
Edit 1
如果.values()调用返回实际的相关模型对象而不仅仅是它们的ID值,这将很容易 .
即我认为这样的查询:
X.objects.all.values('y')
...应该返回包含Y对象而不是Y ID的字典列表 .
像这样的查询:
X.objects.all.values('y_id')
...应该返回包含ID的字典列表,因为它是您要求的 .
有人同意我的意见吗?
1 回答
X.objects.annotate(temp=Sum('b')).select_related('y','z')
适合你吗?select_related docs
编辑:刚刚看到你在你的问题中排除了这一点 . 我没试过,但是
values_list()
可能会返回外键字段的模型实例吗?如果没有,并且你在使用values()
的原因是模型X上有很多不需要的字段,可以考虑使用defer/only