prefetch_related for multiple Levels
Solution 1:
Since Django 1.7, instances of django.db.models.Prefetch
class can be used as an argument of .prefetch_related
. Prefetch
object constructor has a queryset
argument that allows to specify nested multiple levels prefetches like that:
Project.objects.filter(
is_main_section=True
).select_related(
'project_group'
).prefetch_related(
Prefetch(
'project_group__project_set',
queryset=Project.objects.prefetch_related(
Prefetch(
'projectmember_set',
to_attr='projectmember_list'
)
),
to_attr='project_list'
)
)
It is stored into attributes with _list
suffix because I use ListQuerySet
to process prefetch results (filter / order).
Solution 2:
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')