prefetch_related用于多个级别

问题描述 投票:22回答:2

如果我的模型看起来像:

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
2个回答
27
投票
  1. 不,你不能使用select_related作为反向关系。 select_related执行SQL连接,因此主查询集中的单个记录需要在相关表中引用一个(ForeignKeyOneToOne字段)。 prefetch_related实际上做了一个完全独立的第二个查询,缓存结果,然后将它“连接”到python中的查询集中。所以它需要ManyToMany或反向ForeignKey领域。
  2. 您是否尝试过两个下划线来进行多级预取?像这样:Publisher.objects.all().prefetch_related('book_set', 'book_set__page_set')

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来处理预取结果(过滤器/顺序)。

© www.soinside.com 2019 - 2024. All rights reserved.