7

我看到QuerySet该类有 2 种不同的方法,它们似乎具有相同的目的(除非我弄错了):.__nonzero__.exists. (是的,我知道这.__nonzero__bool.)

我的问题:如果这两种方法都只是检查查询集中是否有任何对象,为什么它们有不同的实现?

Django 文档说QuerySet.__nonzero__

注意:如果您只想确定是否存在至少一个结果,并且不需要实际对象,请不要使用此选项。使用 exists() 更有效(见下文)。

(我没有在“下面”找到任何有见地的东西。)

为什么执行QuerySet.__nonzero__效率不高?它是否试图实现与 不同的东西.exists?Django 开发人员不这样做的原因是什么__nonzero__ = exists

4

1 回答 1

8

Why does QuerySet.nonzero have a non-efficient implementation? Is it trying to achieve something different than .exists? What is the reason that the Django developers don't do nonzero = exists?

I think it's because exists is only efficient under certain circumstances.

Imagine this common scenario if __nonzero__ had the "efficient" implementation.

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__ also evaluates the query and stores results in cache. That means all results are stored in memory.

exists only cares about 1 row, and doesn't even instantiate a django object or even store its result in cache.

It seems useful if you are only checking if something exists, and don't need the data in any way.

Why don't the devs make __nonzero__ == exists?

Because exists assumes you don't care about the results. If __nonzero__ called exists, we'd have no results. If exists called __nonzero__, we'd collect results (potentially a lot) just to check if a row exists or not.

Examples:

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.
于 2013-01-16T23:25:18.180 回答