2016-01-29 103 views
2

我有以下型號Django的prefetch_related與M2M通過關係

class Film(models.Model): 
    crew = models.ManyToManyField('Person', through='Role', blank=True) 

class Role(models.Model): 
    person = models.ForeignKey('Person') 
    film = models.ForeignKey('Film') 
    person_role = models.ForeignKey(RoleType) 
    credit = models.CharField(max_length=200) 
    credited_as = models.CharField(max_length=100) 

class RoleType(models.Model): 
    """Actor, director, makeup artist...""" 
    name = models.CharField(max_length=50) 

class Person(models.Model): 
    slug = models.SlugField(max_length=30, unique=True, null=True) 
    full_name = models.CharField(max_length=255) 

一個Film(「星球大戰:克隆人戰爭」)有幾個Person(「克里斯托弗·李」),他們每個人可以有一個或更多Role(「杜庫伯爵之聲」),並且每個Role都有一個RoleType(「聲優」)。

我使用的DetailView顯示Film

class FilmDetail(DetailView): 
    model = Film 

在我的模板我展示所有的人,所以每次我告訴正在執行一個電影609查詢。爲了減少這一點,我想用prefetch_related所以我改變了看法到:

class FilmDetail(DetailView): 
    model = Film 

    def get_queryset(self): 
     return super(FilmDetail, self).get_queryset().prefetch_related('crew') 

但這並沒有減少查詢(610)的數量,我嘗試以下參數預取相關,並沒有奏效:

def get_queryset(self): 
     return super(FilmDetail, self).get_queryset().prefetch_related('crew__person_role') 

我得到了一個錯誤Cannot find 'person_role' on Person object, 'crew__person_role' is an invalid parameter to prefetch_related()

我能做些什麼,從Film.crew預取Person.full_nameslug和所有Role領域?

回答

3

您可以構建您的查詢集這樣的:

from django.db.models import Prefetch 

def get_queryset(self): 
    return super(FilmDetail, self).get_queryset().prefetch_related(
     Prefetch(
      'crew', 
      queryset=Role.objects.select_related(
       'person', 
       'person_role', 
      ), 
     ), 
    ) 

只有成膜>角色是一個向後的關係,其可以裝載prefetch_related。角色 - >角色類型和角色 - >人員是您以select_related加載的轉發關係。