official site:
https://docs.djangoproject.com/en/2.0/ref/models/querysets/#django.db.models.query.QuerySet.select_related
Differences between the two of them:
select_related
works by creating an SQL join and including the fields of the related object in the SELECT
statement. For this reason, select_related
gets the related objects in the same database query. However, to avoid the much larger result set that would result from joining across a ‘many’ relationship, select_related
is limited to single-valued relationships - foreign key and one-to-one.
prefetch_related
, on the other hand, does a separate lookup for each relationship, and does the ‘joining’ in Python. This allows it to prefetch many-to-many and many-to-one objects, which cannot be done using select_related
, in addition to the foreign key and one-to-one relationships that are supported by select_related
. It also supports prefetching ofGenericRelation
and GenericForeignKey
, however, it must be restricted to a homogeneous set of results. For example, prefetching objects referenced by a GenericForeignKey
is only supported if the query is restricted to one ContentType
.
Select_related
The following examples illustrate the difference between plain lookups and select_related() lookups. Here’s standard lookup:
# Hits the database.
e = Entry.objects.get(id=5)
# Hits the database again to get the related Blog object.
b = e.blog
And here’s select_related lookup:
# 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
You can follow foreign keys in a similar way to querying them. If you have the following models:
from django.db import models
class City(models.Model):
# ...
pass
class Person(models.Model):
# ...
hometown = models.ForeignKey(
City,
on_delete=models.SET_NULL,
blank=True,
null=True,
)
class Book(models.Model):
# ...
author = models.ForeignKey(Person, on_delete=models.CASCADE)
… then a call to Book.objects.select_related('author__hometown').get(id=4) will cache the related Person and the related City:
# Hits the database with joins to the author and hometown tables.
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.
# Without select_related()...
b = Book.objects.get(id=4) # Hits the database.
p = b.author # Hits the database.
c = p.hometown # Hits the database.
prefetch_related
For example, suppose you have these models:
from django.db import models
class Topping(models.Model):
name = models.CharField(max_length=30)
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
def __str__(self):
return "%s (%s)" % (
self.name,
", ".join(topping.name for topping in self.toppings.all()),
)
and run:
>>> Pizza.objects.all()
["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...
The problem with this is that every time Pizza.str() asks for self.toppings.all() it has to query the database, so Pizza.objects.all() will run a query on the Toppings table for every item in the Pizza QuerySet.
We can reduce to just two queries using prefetch_related:
>>> Pizza.objects.all().prefetch_related('toppings')
This implies a self.toppings.all()
for each Pizza
; now each time self.toppings.all()
is called, instead of having to go to the database for the items, it will find them in a prefetched QuerySet
cache that was populated in a single query.
That is, all the relevant toppings will have been fetched in a single query, and used to make QuerySets
that have a pre-filled cache of the relevant results; these QuerySets
are then used in the self.toppings.all()
calls.
The additional queries in prefetch_related()
are executed after the QuerySet
has begun to be evaluated and the primary query has been executed.
If you have an iterable of model instances, you can prefetch related attributes on those instances using the prefetch_related_objects()
function.
Note that the result cache of the primary QuerySet
and all specified related objects will then be fully loaded into memory. This changes the typical behavior of QuerySets
, which normally try to avoid loading all objects into memory before they are needed, even after a query has been executed in the database.