Django QuerySet

A QuerySet is the collection of database rows Django gives you back when you ask a model for data, and it stays lazy until you actually force it to run.

What Is a QuerySet?

Every time you call a manager method like Model.objects.all() or Model.objects.filter(), Django hands you back a QuerySet instead of a plain Python list. A QuerySet represents a collection of rows from the database, but it is really just a description of a query -- it does not contain any data until it is evaluated.

Example

from myapp.models import Book

# Get every row in the Book table as a QuerySet
all_books = Book.objects.all()
print(type(all_books))
# <class 'django.db.models.query.QuerySet'>

for book in all_books:
    print(book.title)

Lazy Evaluation

Building a QuerySet with all(), filter(), exclude(), or order_by() never touches the database by itself. Django waits as long as possible and only sends SQL to the database when the result is actually needed, which is why this behavior is called lazy evaluation.

  • Iterating over the QuerySet in a for loop
  • Calling list(), len(), or bool() on it
  • Slicing it with a step, such as queryset[0:10:2]
  • Printing it in the shell, which calls repr()

Example

# Building a queryset does NOT hit the database yet
queryset = Book.objects.all()
queryset = queryset.filter(is_published=True)
queryset = queryset.order_by('-published_date')

# The SQL only runs once the queryset is evaluated,
# for example by looping over it or calling list()
recent_books = list(queryset)  # database hit happens here

Chaining and Caching

Methods such as filter(), exclude(), and order_by() each return a brand new QuerySet, so calls can be chained together to build up a query step by step. Once a QuerySet has been evaluated, Django caches the results on that QuerySet instance, so reusing the same variable avoids repeating the query.

Example

books = Book.objects.filter(is_published=True)

print(len(books))   # evaluates the queryset once, result is cached

for book in books:  # reuses the cached result, no new query
    print(book.title)

print(books.count())  # count() runs its own SQL COUNT query
MethodWhat It Returns
all()A QuerySet containing every row
filter(**kwargs)A QuerySet matching the given lookups
get(**kwargs)A single model instance, or raises an error
count()An integer, not a QuerySet
first() / last()A single model instance or None
Note: Book.objects.filter(...) called twice creates two separate QuerySets, each with its own cache. Store the result in a variable if you plan to reuse it, otherwise Django will run the same query again.

Exercise: Django QuerySet

What does Model.objects.all() return?