2014-11-25 154 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後綴。