Django:`QuerySet.__nonzero__` 和 `QuerySet.exists` 之间有什么区别吗?

7
我看到`QuerySet`类有两个不同的方法似乎服务于相同的目的(除非我错了):`.__nonzero__`和`.exists`。(是的,我知道`.__nonzero__`被`bool`使用。)
我的问题是:如果它们都只是检查查询集中是否有任何对象,为什么这两种方法有不同的实现方式?
Django文档关于`QuerySet.__nonzero__`的说法如下:
注意:如果你只想确定是否存在至少一个结果,并且不需要实际的对象,请不要使用此方法。使用exists()更有效(见下文)。
(我没有发现有什么有深度的“下文”。)
为什么`QuerySet.__nonzero__`具有低效的实现? 它是否试图实现与` .exists`不同的功能? Django开发人员为什么不做`__nonzero__ = exists`?

我认为__nonzero__会评估QuerySet,而exists则会执行特殊的查询到数据库后端。 - Wessie
1个回答

8
为什么QuerySet.nonzero的实现不够高效?它与.exists有什么不同的目的?为什么Django开发人员不使用nonzero=exists呢?
我认为这是因为exists仅在特定情况下才有效率。
想象一下如果__nonzero__已经有了"高效"的实现,那么常见的情况就如下所示。
foos = Foo.objects.filter(bar='baz')

if foos:   # nonzero() calls exists() which causes extra query
           # even though the QS is already going to be evaluated
           # which in my projects is a common pattern. 
   print "Yay for foos!"
   for foo in foos:
       print foo

__nonzero__ 也会评估查询并将结果存储在缓存中。这意味着所有结果都存储在内存中。

exists 仅关心1行,并且甚至不会实例化django对象或将其结果存储在缓存中。

如果您只想检查某些内容是否存在且不需要数据,则似乎非常有用。

为什么开发人员不将 __nonzero__ 等于 exists

因为 exists 假设您不关心结果。如果 __nonzero__ 调用 exists,我们将没有结果。如果 exists 调用 __nonzero__,我们将收集结果(可能很多),仅仅是为了检查一行是否存在。

示例:

bool( Foo.objects.filter(user=user) )  
# calls __nonzero__, evaluates, converts all fields to python objects 
# and stores in queryset._result_cache


Foo.objects.filter(user=user).exists()
# stores nothing, and query only returns one row.
# less data from DB and less python overhead generating django model instances.

你可以将这个决定解释为“显式优于隐式”。Django只会执行你要求的查询。这同样适用于count()__len__。数据库优化文档还提供了一个有用的例子:https://docs.djangoproject.com/en/dev/topics/db/optimization/#don-t-overuse-count-and-exists - spookylukey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接