强制进行Django查询的INNER JOIN

时间:2012-07-23 20:05:42

标签: python sql django orm

这是我的架构:

城市 - >摄影师

我正在尝试获取至少有一位摄影师的城市名单,并返回城市的摄影师人数。

以下是我正在使用的查询集:

City.objects.annotate(photographer_count=aggregates.Count('photographers')).filter(photographer_count__gt=0).order_by('-photographer_count')

这完全符合我的预期,除了某些原因,Django选择在城市/摄影师与左外连接之间进行连接。如果我抓取SQL文本并简单地将“left outer”更改为“inner”,则查询从~11秒变为200ms,结果相同。

我已经尝试在注释前面添加一个过滤器,向Django暗示它应该是内部连接,但这不起作用。

我可以对此执行任何Django查询voodoo以获得内部联接吗?我意识到我可以使用直接SQL,但更愿意通过ORM。

2 个答案:

答案 0 :(得分:6)

默认情况下,会生成LEFT JOIN,这样Django即使对于没有摄影师的城市也能获得行。如果你知道你不想要那些,这就是强制Django生成INNER JOIN的技巧:

City.objects.filter(
    photographer__isnull=False
).annotate(
    photographer_count=aggregates.Count('photographers')
).filter(
    photographer_count__gt=0
).order_by(
    '-photographer_count'
)

具体来说,第一个过滤器告诉Django INNER JOIN是安全的。 必须来到annotate()来电之前。

答案 1 :(得分:1)

您通常无法对Django执行的查询和连接进行此级别的控制。

Django并没有做一些非常聪明的事情,比如注意到过滤条件意味着你可以在这一点上使用INNER JOIN - 它必须产生一般情况下正确的查询,在这种情况下意味着LEFT就我所知,外联接。

所以你可能需要原始的SQL。