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 连接,因此主查询集中的一条记录需要准确引用相关表中的一条记录(ForeignKeyOneToOne 字段)。 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

AttributeError:“Resume”对象没有“prefetch_related”属性

Django:prefetch_related 没有效果

Django:prefetch_related() 是不是遵循反向关系查找?