Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: Any difference between `QuerySet.__nonzero__` and `QuerySet.exists`?

Tags:

python

django

I see that the QuerySet class has 2 different methods that seem to serve the same purpose (unless I'm mistaken): .__nonzero__ and .exists. (Yes, I know that .__nonzero__ is used by bool.)

My question: Why do the 2 methods have different implementation if they both just check whether there's any object in the queryset?

The Django documentation says about QuerySet.__nonzero__:

Note: Don't use this if all you want to do is determine if at least one result exists, and don't need the actual objects. It's more efficient to use exists() (see below).

(I didn't find anything insightful "below".)

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?

like image 752
Ram Rachum Avatar asked Jan 16 '13 21:01

Ram Rachum


Video Answer


1 Answers

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.
like image 194
Yuji 'Tomita' Tomita Avatar answered Oct 21 '22 03:10

Yuji 'Tomita' Tomita