Django prefetch_related与m2m通过关系

fas*_*uto 5 django django-models django-queryset

我有以下型号

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)
Run Code Online (Sandbox Code Playgroud)

A Film("星球大战:克隆人战争")有几个Person("克里斯托弗李"),每个人都可以拥有一个或多个Role("杜库伯爵之声"),每个人Role都有一个RoleType("配音演员").

我正在使用DetailView来显示 Film

class FilmDetail(DetailView):
    model = Film
Run Code Online (Sandbox Code Playgroud)

在我的模板中,我显示所有人,所以每次我显示一个电影609查询正在执行.为了减少这种情况,我想使用,prefetch_related所以我将视图更改为:

class FilmDetail(DetailView):
    model = Film

    def get_queryset(self):
        return super(FilmDetail, self).get_queryset().prefetch_related('crew')
Run Code Online (Sandbox Code Playgroud)

但是这并没有减少查询次数(610),我尝试了以下参数来预取相关的内容并且它不起作用:

def get_queryset(self):
        return super(FilmDetail, self).get_queryset().prefetch_related('crew__person_role')
Run Code Online (Sandbox Code Playgroud)

我收到了一个Cannot find 'person_role' on Person object, 'crew__person_role' is an invalid parameter to prefetch_related()错误

我能做些什么,以预取Person.full_nameslug所有Role领域的Film.crew

Tom*_*lch 8

您可以像这样构造您的查询集:

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',
            ),
        ),
    )
Run Code Online (Sandbox Code Playgroud)

只有电影 - >角色是可以加载的向后关系prefetch_related.Role-> RoleType和Role-> Person是您加载的转发关系select_related.