Django ORM如何在WHERE语句中进行聚合子查询?

问题描述 投票:0回答:2

我正在尝试构建类似于 Django ORM 的以下查询:

SELECT * FROM table WHERE depth = (SELECT MIN(depth) FROM table)

这怎么能用 Django ORM 符号来写?到目前为止,似乎很难使用这样的聚合,因为

QuerySet.aggregate()
不是惰性评估,而是直接执行。

我知道这个基本示例可以写成

Model.objects.filter(depth=Model.objects.aggregate(m=Min('depth'))['m'])
但它不会延迟评估,需要 2 个单独的查询。对于我更复杂的情况,我绝对需要一个延迟评估的查询集。


仅供参考,我尝试过但失败的事情:

  • 带有
    Model.objects.order_by().values().annotate(m=Min('depth').values('m'))
    的子查询将导致
    GROUP BY id
    似乎很难丢失。
  • 带有
    Model.objects.annotate(m=Min('depth')).filter(depth=F('m'))
    的子查询将给出
    GROUP BY id
    ,并在主要结果中包含
    m
    值,因为这就是注释所做的。

我目前的解决方法是使用

QuerySet.extra(where=[...])
但我更愿意看到 ORM 生成该代码。

python django django-orm
2个回答
0
投票

这应该有效

MyModel.objects.filter(
    depth=MyModel.objects.annotate(min_depth=Min('depth)).values('min_depth')[:1]
)

使用注释而不是聚合将使查询集保持惰性。


0
投票

根据@Brad 的建议,这似乎确实可以作为替代方案:

MyModel.objects.filter(
    depth=MyModel.objects.order_by('depth').values('depth')[:1]
)

它本质上变成了这个SQL:

SELECT * FROM table WHERE depth = (SELECT depth FROM table ORDER BY depth LIMIT 1)
© www.soinside.com 2019 - 2024. All rights reserved.