首页 文章

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

提问于
浏览
2

说我有三个型号:

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 回答

  • 1

    X.objects.annotate(temp=Sum('b')).select_related('y','z') 适合你吗?

    select_related docs

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

相关问题