2016-01-29 63 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加载的转发关系。