Skip to content

Instantly share code, notes, and snippets.

@101t
Last active February 18, 2019 18:17
Show Gist options
  • Save 101t/7eba51acc745ef1505d82c8daba554b0 to your computer and use it in GitHub Desktop.
Save 101t/7eba51acc745ef1505d82c8daba554b0 to your computer and use it in GitHub Desktop.
Django QuerySets

Cheatsheet for Django QuerySets

Current Django Version: 1.11

Methods that return new QuerySets

Can be chained:

Entry.objects.filter(**kwargs).exclude(**kwargs).order_by(**kwargs)
Entry.objects.filter(id__in=[1, 3, 4])
SELECT ... WHERE id IN (1, 3, 4);

inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3))/
.exclude(headline='Hello')
SELECT ... WHERE NOT pub_date > '2005-1-3' AND NOT headline = 'Hello'
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42

>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
The result above will be ordered by pub_date descending, 
then by headline ascending. 
The negative sign in front   of "-pub_date" indicates descending order. 
Ascending order is implied. 

# No Join
Entry.objects.order_by('blog_id')
# Join
Entry.objects.order_by('blog__id')
Use the reverse() method to reverse the order in 
which a querysets elements are returned. 
Calling reverse() a second time restores the ordering back to the normal direction.

my_queryset.reverse()[:5]
When using distinct() and values() together, be careful when ordering by fields
not in the values() call.

When you specify field names, you must provide an order_by() in the QuerySet, 
and the fields in order_by() must  start with the fields in distinct(), 
in the same order.

Author.objects.distinct()

Entry.objects.order_by('pub_date').distinct('pub_date')

Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
Blog.objects.filter(name__startswith='Beatles').values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]

Entry.objects.values('blog_id')
[{'blog_id': 1}, ...]

Blog.objects.values('name', 'entry__headline')
[{'name': 'My blog', 'entry__headline': 'An entry'},
    {'name': 'My blog', 'entry__headline': 'Another entry'}, ...]
Entry.objects.values_list('id', 'headline')
[(1, 'First entry'), ...]

Entry.objects.values_list('id', flat=True).order_by('id')
[1, 2, 3, ...]
field should be the name of a DateField of your model. 
kind should be either "year", "month" or "day". 
Each datetime.date object in the result list istruncatedto the given type.

* "year" returns a list of all distinct year values for the field.
* "month" returns a list of all distinct year/month values for the field.
* "day" returns a list of all distinct year/month/day values for the field.

Entry.objects.dates('pub_date', 'year')
[datetime.date(2005, 1, 1)]

Entry.objects.dates('pub_date', 'month')
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]

Entry.objects.dates('pub_date', 'day')
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]

Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
tzinfo defines the time zone to which datetimes are converted prior to truncation. 
Indeed, a given datetime has different representations depending on the time zone in use. 
This parameter must be a datetime.tzinfo object. 
If its None, Django uses the current time zone. It has no effect when USE_TZ is False.

This function performs time zone conversions directly in the database. 
As a consequence, your database must be able to interpret the value of tzinfo.tzname(None). 
This translates into the following requirements:

* SQLite: install pytzconversions are actually performed in Python.
* PostgreSQL: no requirements (see Time Zones).
* Oracle: no requirements (see Choosing a Time Zone File).
* MySQL: install pytz and load the time zone tables with mysql_tzinfo_to_sql.
Calling none() will create a queryset that never returns any objects and 
no query will be executed when accessing the results. 
A qs.none() queryset is an instance of EmptyQuerySet.

Entry.objects.none()
[]

from django.db.models.query import EmptyQuerySet
isinstance(Entry.objects.none(), EmptyQuerySet)
True
Returns a copy of the current QuerySet (or QuerySet subclass).
When a QuerySet is evaluated, it typically caches its results. 
If the data in the database might have changed since a QuerySet was evaluated, 
you can get updated results for the same query by calling all() 
on a previously evaluated QuerySet.
e = Entry.objects.get(id=5) # Hits the database.
b = e.blog # Hits the database again to get the related Blog object.

# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)

# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog

b = Book.objects.select_related('author__hometown').get(id=4)
p = b.author         # Doesn't hit the database.
c = p.hometown       # Doesn't hit the database.

b = Book.objects.get(id=4) # No select_related() in this example.
p = b.author         # Hits the database.
c = p.hometown       # Hits the database.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment