If my Models look like:
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(Publisher)
class Page(models.Model):
book = models.ForeignKey(Book)
and I would like to get the queryset for Publisher
I do Publisher.object.all()
.
If then want to make sure to prefetch I can do:
Publisher.objects.all().prefetch_related('book_set')`
My questions are:
- Is there a way to do this prefetching using
select_related
or must I useprefetch_related
? - Is there a way to prefetch the
page_set
? This does not work:
Publisher.objects.all().prefetch_related('book_set', 'book_set_page_set')
Since Django 1.7, instances of
django.db.models.Prefetch
class can be used as an argument of.prefetch_related
.Prefetch
object constructor has aqueryset
argument that allows to specify nested multiple levels prefetches like that:It is stored into attributes with
_list
suffix because I useListQuerySet
to process prefetch results (filter / order).No, you cannot use
select_related
for a reverse relation.select_related
does a SQL join, so a single record in the main queryset needs to reference exactly one in the related table (ForeignKey
orOneToOne
fields).prefetch_related
actually does a totally separate second query, caches the results, then "joins" it into the queryset in python. So it is needed forManyToMany
or reverseForeignKey
fields.Have you tried two underscores to do the multi level prefetches? Like this:
Publisher.objects.all().prefetch_related('book_set', 'book_set__page_set')