Django. 从查询集中删除select_related

3 投票
2 回答
3230 浏览
提问于 2025-04-17 09:55

有没有办法从查询集中去掉选择相关的内容?

我发现,Django在执行count()操作时,会在SQL查询中添加JOIN。 所以,如果我们有这样的代码:

entities = Entities.objects.select_related('subentity').all()
#We will have INNER JOIN here..
entities.count()

我在寻找一种方法来去掉这个连接。 有一个重要的细节 - 我把这个查询集放进了Django的分页器里,所以我不能简单地写

Entities.objects.all().count()

2 个回答

9

我觉得这段代码的注释对这里提到的一般问题提供了一个相对不错的答案:

如果调用了 select_related(None),那么列表会被清空。

https://github.com/django/django/blob/stable/1.8.x/django/db/models/query.py#L735

一般来说,如果你想对 entities 这个查询集做点什么,但又想先把里面的 select_related 项目去掉,可以用 entities.select_related(None)

不过,这可能并不能解决你在使用分页器时遇到的具体问题。如果你执行 entries.count(),那么它 已经会 去掉 select_related 的项目了。如果你发现有多余的 JOIN 操作,那可能是因为一些不理想的因素。可能是 ORM 没有去掉这些项,因为其他逻辑可能会影响计数,尤其是和 select_related 结合时。

举个简单的例子,看看 Foo.objects.select_related('bar').count()Foo.objects.select_related('bar').distinct().count() 的区别。你可能会觉得原来的查询集没有重复的条目,但 Django 的 ORM 并不这么认为。因此,执行的 SQL 会包含一个 JOIN,而没有通用的方法来解决这个问题。即使你使用 .select_related(None) 也不会有帮助。

1

你能把需要这个的代码给我看看吗?我觉得重构代码是最好的解决办法。

如果你想要快速的答案,可以用 entities.query.select_related = False,不过这个方法有点不太正规(而且如果以后还需要用到 select_related,记得要把这个值恢复回来)。

撰写回答