prefetch_related 多个级别
Posted
技术标签:
【中文标题】prefetch_related 多个级别【英文标题】:prefetch_related for multiple Levels 【发布时间】:2015-01-22 20:52:15 【问题描述】:如果我的模型看起来像:
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
或
我必须使用prefetch_related
吗?
有没有办法预取
page_set
?这不起作用:
Publisher.objects.all().prefetch_related('book_set', 'book_set_page_set')
【问题讨论】:
【参考方案1】:从 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'
)
)
由于我使用ListQuerySet
处理预取结果(过滤/排序),所以存储到带有_list
后缀的属性中。
【讨论】:
这是一个非常棒的答案,可以让您节省大量的数据库流量。我不明白为什么这个答案没有引起太多关注 见github.com/Dmitri-Sintsov/django-jinja-knockout/… 嗨@DmitriySintsov 我可以在这里得到你的帮助吗:- ***.com/questions/68682472/…【参考方案2】:不,您不能将select_related
用于反向关系。 select_related
执行 SQL 连接,因此主查询集中的一条记录需要准确引用相关表中的一条记录(ForeignKey
或 OneToOne
字段)。 prefetch_related
实际上做了一个完全独立的第二个查询,缓存结果,然后将其“加入”到 python 中的查询集中。所以ManyToMany
或反向ForeignKey
字段需要它。
您是否尝试过使用两个下划线来执行多级预取?像这样:Publisher.objects.all().prefetch_related('book_set', 'book_set__page_set')
【讨论】:
1.如果Page
有一个OneToOne
字段到TextContent
,它会是:...prefetch_related('book_set__page_set__text_contents')
或...select_related('book_set__page_set__text_contents')
我相信它会是第二个版本。以上是关于prefetch_related 多个级别的主要内容,如果未能解决你的问题,请参考以下文章
084:QuerySet API详解prefetch_related方法
如何使用 prefetch_related 获取 Django 相关模型中的最新位置
django- 在另一个 prefetch_related 中使用 prefetch_related