我在Django项目中具有以下模型:
class Category(models.Model):
title = models.CharField(max_length=255)
def __str__(self):
return '{} - {}'.format(self.pk, self.title)
class Item(models.Model):
title = models.CharField(max_length=255)
categories = models.ManyToManyField(Category)
def __str__(self):
return '{} - {}'.format(self.pk, self.title)
我创建了一个项目,并将其与两个类别相关联:
>>> item1 = Item.objects.get(pk=1)
>>> item1.categories.all()
<QuerySet [<Category: 1 - C1>, <Category: 4 - C4>]>
我还可以使用filter()并获得预期的结果:
>>> Item.objects.filter(categories__title='C1')
<QuerySet [<Item: 1 - Item1>]>
但是,当我在同一查询集上使用values()时,将仅返回已过滤的关系:
>>> Item.objects.filter(categories__title='C1').values('categories__title')
<QuerySet [{'categories__title': 'C1'}]>
相比:
>>> Item.objects.all().values('categories__title')
<QuerySet [{'categories__title': 'C1'}, {'categories__title': 'C4'}]>
我想念什么?如何获取类别的完整列表?
答案 0 :(得分:0)
values
在多对多关系中无法正常工作。您的过滤器实际上是在中间表上创建一个INNER JOIN(它跟踪多对多关系),并且在过滤掉所有相关模型之后将应用values
。因此,它不会为您返回每个Item
对象的所有类别,而只会返回经过过滤的类别。
您应该颠倒您的工作顺序:
Item.objects.values('categories__title').filter(categories__title="C1")
这实际上将首先创建一个附加的LEFT OUTER JOIN,然后为过滤子句添加INNER JOIN。
请注意,如果过滤器返回了多个项目,那么如果对象的类别重叠,则最终会导致类别标题的重复值很多。参见warning at the end of this section