如何让 fetch_related 在基于 class 的视图上工作?

How to make fetch_related work on class-based View?

我真的很喜欢 CBV 方法,但似乎无法在这种情况下使用它。 TeamPerson 模型通过 Player 模型通过 players M2M 关系连接。

class Person(Model):
    last_name = CharField(max_length=30)
    ...
class Team(Model):
    players = ManyToManyField(Person, through='Player')
    ...
class Player(Model):
    person = ForeignKey(Person)
    team = ForeignKey(Team)
    date_joined = DateField()
    ...

球队详细信息页面上带有姓名和 date_joined 的球队名单对每个球员进行一次查询,因此我预取球员数据:

def team_detail_view(request, pk=None):
    ...
    team = Team.objects.get(pk=pk)
    roster = team.player_set.all().prefetch_related('person')
    return render_to_response('team_detail.html', 
        {'object': team, 'roster': roster}, ...)

如何使用 CBV prefetch_related?我在 django-braces 中找到了 PrefetchRelatedMixin,但是当我找到

class TeamDetailView(PrefetchRelatedMixin, DetailView):
    prefetch_related = [u'players']
    model = Team

这仍然为模板中的每个玩家提供了单独的查询

{% for player in object.player_set %}
<tr><td>{{ player.person.last_name }}</td><td>{{ player.date_joined }}</td></tr>
{% endfor %}

似乎需要一种在团队模型的 M2M 字段上调用 ​​prefetch_related 的方法,而不是在团队本身上。可以用CBV来完成吗?

您是否尝试过覆盖 get_queryset()?

class TeamDetailView(DetailView):
    ...

    def get_queryset(self):
        return self.queryset.prefetch_related('players').all()

DetailView 在 self.get() 而不是 self.get_queryset() 上运行,您的 Mixin 会在其中过载。您必须修改 PrefetchRelatedMixin 以支持 get() 上的 prefetch_related 属性。

原来

class TeamDetailView(PrefetchRelatedMixin, DetailView):
    prefetch_related = ['player_set__person']
    model = Team

虽然我不完全确定它的机制,但确实有效。