【问题标题】:prefetch_related for multiple Levelsprefetch_related 多个级别
【发布时间】: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')`

我的问题是:

  1. 有没有办法使用select_related 或 我必须使用prefetch_related吗?
  2. 有没有办法预取 page_set?这不起作用:

Publisher.objects.all().prefetch_related('book_set', 'book_set_page_set')

【问题讨论】:

    标签: django django-queryset django-orm


    【解决方案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后缀的属性中。

    【讨论】:

    【解决方案2】:
    1. 不,您不能将select_related 用于反向关系。 select_related 执行 SQL 连接,因此主查询集中的一条记录需要准确引用相关表中的一条记录(ForeignKeyOneToOne 字段)。 prefetch_related 实际上做了一个完全独立的第二个查询,缓存结果,然后将其“加入”到 python 中的查询集中。所以ManyToMany或反向ForeignKey字段需要它。

    2. 您是否尝试过使用两个下划线来执行多级预取?像这样: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')
    • 我相信它会是第二个版本。
    猜你喜欢
    • 2015-03-04
    • 1970-01-01
    • 2019-01-09
    • 2013-11-23
    • 2016-11-28
    • 1970-01-01
    • 2019-03-30
    • 2021-11-08
    • 1970-01-01
    相关资源
    最近更新 更多