如果我的模特看起来像:
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(Publisher)
class Page(models.Model):
book = models.ForeignKey(Book)
我想获得Publisher
我Publisher.object.all()
的查询集。
如果那时想确保预取我可以做:
Publisher.objects.all().prefetch_related('book_set')`
我的问题是:
select_related
或{pre}执行此预取
我必须使用prefetch_related
吗?page_set
?这不起作用: Publisher.objects.all().prefetch_related('book_set', 'book_set_page_set')
答案 0 :(得分:27)
不,您不能将select_related
用于反向关系。 select_related
执行SQL连接,因此主查询集中的单个记录只需引用相关表(ForeignKey
或OneToOne
字段中的一个记录)。 prefetch_related
实际上做了一个完全独立的第二个查询,缓存结果,然后将它“连接”到python中的查询集中。因此,ManyToMany
或反向ForeignKey
字段需要它。
您是否尝试过两个下划线来执行多级预取?像这样:Publisher.objects.all().prefetch_related('book_set', 'book_set__page_set')
答案 1 :(得分:15)
自Django 1.7以来,django.db.models.Prefetch
类的实例可以用作.prefetch_related
的参数。 Prefetch
对象构造函数有一个queryset
参数,允许指定嵌套的多个级别预取:
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'
)
)
它存储在_list
后缀的属性中,因为我使用ListQuerySet
来处理预取结果(过滤器/顺序)。