Django:如何过滤具有多对多关系的模型

Django: how to filter a model with ManyToMany relationships

我有一个通用的 ListView,我从中得到了一些通用的东西(这与我的问题无关)。

我的模型 ProductTag 有多对多关系,即一个 Product 可以有多个 Tag 并且一个 Tag 可以链接到许多 Product.

在这个通用的 ListView 中,我想过滤所有实际上有 ProductTag,这样客户可以点击 Tag,我可以稍后进行过滤。

到目前为止我是这样的:

class IndexView(generic.ListView):
    template_name = 'produits/index.html'
    context_object_name = 'liste_produits'

    def get_queryset(self):
        """Return the last five created products."""
        return Produit.objects.order_by('-date_v_fin', '-date_v_debut')[:5]

    def get_context_data(self, **kwargs):
        context = super(IndexView, self).get_context_data(**kwargs)
        context['produits_tags'] = list(
            Tag.objects.values_list('nom', flat=True)
        )
        context['produits_tags'].insert(0, _("Tous"))
        return context

但是Tag.objects.values_list('nom', flat=True)returns全部Tag,包括没有的Product。如何过滤?

试试这个:

Tag.objects.filter(product_set__isnull=False).values_list('nom', flat=True)

找到了!首先,通过像这样使用 related_name 让 ManyToMany 关系更易读:

class Produit(BaseModel):
    tags = models.ManyToManyField(Tag, related_name='produits')

然后这就是我如何获得 Produit 使用的所有 Tag。我想它不是很优化,但它很有魅力:

class IndexView(generic.ListView):
    #blabbla ignoring code in-between
    def get_context_data(self, **kwargs):
        context = super(IndexView, self).get_context_data(**kwargs)
        context['produits_tags'] = list(
            Tag.objects.filter(produits__in=Produit.objects.all()).distinct()
        )
        context['produits_tags'].insert(0, _("All"))
        return context