Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Django, what is the most efficient way to check for an empty query set?

Tags:

I've heard suggestions to use the following:

if qs.exists():     ...  if qs.count():     ...  try:     qs[0] except IndexError:     ... 

Copied from comment below: "I'm looking for a statement like "In MySQL and PostgreSQL count() is faster for short queries, exists() is faster for long queries, and use QuerySet[0] when it's likely that you're going to need the first element and you want to check that it exists. However, when count() is faster it's only marginally faster so it's advisable to always use exists() when choosing between the two."

like image 333
Sam Odio Avatar asked Jul 29 '11 05:07

Sam Odio


People also ask

Why Django QuerySets are lazy?

This is because a Django QuerySet is a lazy object. It contains all of the information it needs to populate itself from the database, but will not actually do so until the information is needed.

What is query set in Django?

A QuerySet is a collection of data from a database. A QuerySet is built up as a list of objects. QuerySets makes it easier to get the data you actually need, by allowing you to filter and order the data.


1 Answers

query.exists() is the most efficient way.

Especially on postgres count() can be very expensive, sometimes more expensive then a normal select query.

exists() runs a query with no select_related, field selections or sorting and only fetches a single record. This is much faster then counting the entire query with table joins and sorting.

qs[0] would still includes select_related, field selections and sorting; so it would be more expensive.

The Django source code is here (django/db/models/sql/query.py RawQuery.has_results):

https://github.com/django/django/blob/60e52a047e55bc4cd5a93a8bd4d07baed27e9a22/django/db/models/sql/query.py#L499

def has_results(self, using):     q = self.clone()     if not q.distinct:         q.clear_select_clause()     q.clear_ordering(True)     q.set_limits(high=1)     compiler = q.get_compiler(using=using)     return compiler.has_results() 

Another gotcha that got me the other day is invoking a QuerySet in an if statement. That executes and returns the whole query !

If the variable query_set may be None (unset argument to your function) then use:

if query_set is None:     #  

not:

if query_set:    # you just hit the database 
like image 188
Chris Sattinger Avatar answered Nov 17 '22 21:11

Chris Sattinger