2014-11-25 153 views
12

如果我的模式是这样的:prefetch_related为多层次

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')

回答

19
  1. 不,你不能反向关系使用select_relatedselect_related执行SQL连接,因此主要查询集中的单个记录需要在相关表(ForeignKeyOneToOne字段)中恰好引用一个记录。 prefetch_related实际上完成了一个完全独立的第二个查询,缓存结果,然后将它“连接”到python的查询集中。所以需要ManyToMany或反向ForeignKey字段。

  2. 您是否尝试了两次下划线来执行多级预取?像这样:Publisher.objects.all().prefetch_related('book_set', 'book_set__page_set')

+3

2.双下划线的作品。 – 2014-11-25 02:18:08

+0

1.如果'Page'具有'OneToOne'字段到'TextContent',它会是:'... prefetch_related('book_set__page_set__text_contents')'或'... select_related('book_set__page_set__text_contents')' – 2014-11-25 02:20:01

+0

我相信它会成为第二个版本。 – jproffitt 2014-11-25 02:25:12

4

由于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后缀。