如何使用 pk selected 在 ManyToMany 关系中使用 prefetch_related

How to use prefetch_related in a ManyToMany relation using pk selected

如何根据在列表页面上选择的 pk 在详细信息页面中显示电影所属的类别:多对多关系。我正在寻找一种可能的使用 prefetch_related 来完成此操作的方法。其他方式也可以。

models.py

class Movie(models.Model):
    title = models.CharField(max_length=70)
    description = models.TextField(max_length=500)

class Category(models.Model):
    name = models.CharField(max_length=70)
    movie = models.ManyToManyField(Movie, related_name='categories')

views.py

class MovieListView(ListView):
    model = Movie
    context_object_name = 'movies'
    template_name = 'snippets/index.html'

    def get_queryset(self):
        return Movie.objects.all()

class MovieDetailView(DetailView):
    model = Movie
    template_name = 'snippets/detail.html'

如有任何帮助,我们将不胜感激。

您可以将 DetailViewqueryset 更改为:

class MovieDetailView(DetailView):
    model = Movie
    queryset = Movie.objects<b>.prefetch_related('categories')</b>
    template_name = 'snippets/detail.html'
    <b>context_object_name = 'movie_name'</b>

这里不需要过滤,也不需要设置get_context_data。您可以使用 context_object_name 属性指定对象的名称,并且 DetailView [Django-doc] will automatically filter on the primary key given the url contains a pk parameter (as well as on the slug given the url contains a slug parameter). The documentation on get_object [Django-doc] 表示:

Returns the single object that this view will display. If queryset is provided, that queryset will be used as the source of objects; otherwise, get_queryset() will be used. get_object() looks for a pk_url_kwarg argument in the arguments to the view; if this argument is found, this method performs a primary-key based lookup using that value. If this argument is not found, it looks for a slug_url_kwarg argument, and performs a slug lookup using the slug_field.

When query_pk_and_slug is True, get_object() will perform its lookup using both the primary key and the slug.

名称 movie_name 然而有点 "misleading" 因为人们可能认为这是处理名称(string),而这是 Movie目的。也许最好将 context_object_name 设置为 'movie'

请注意,.prefetch_related 仍然需要额外的查询才能将相关类别提取到内存中。因此在视图中使用 movie.categories,将导致相同数量的查询。

在模板中,您可以使用以下类别渲染 movie

{{ movie }}; categories:
{% for category in movie.categories.all %}
    {{ category }}
{% endfor %}