2014-09-13 100 views
1

简单的模型在标签字段上具有多对多关系。Django过滤器推演ManyToMany

class Tag(models.Model): 
    description = models.TextField() 

class Species(models.Model): 
    name = models.CharField(max_length=256) 
    tags = models.ManyToManyField(Tag) 

现在我试着这一点,据我了解,它应该返回一个,每一个tag_description在标签列表匹配列表:

tag_list = request.GET.get('q').split(',') 
species = Species.objects.filter(reduce(and_, [Q(tags__description=c) for c in tag_list])) 

但它返回一个空列表。它应该返回一些对象。

它工作时,我给它只是一个标签

任何想法,为什么发生这种情况?

进出口使用它作为这个答案显示: https://stackoverflow.com/a/8636836/228660

回答

1

正如你在这个问题的意见实际上看到,它实际上并没有工作;) 的问题是,您将使用所有过滤器都使用相同的连接(即相同的对象)。除非tag_list中的所有项目都是相同的,否则这将无法使用。问题在于Q对象而不是完全过滤的查询。

tag_list = request.GET.get('q').split(',') 

# Generate a query with all species 
all_species = Species.objects.all() 
# Generate a list with the separately filtered species 
filtered_species = [all_species.filter(tags__description=c) for c in tag_list] 
# Join the filtered species together using the same method :) 
species = reduce(and_, filtered_species, all_species) 
+0

啊哈,谢谢!但是这会给我一个基于OR的列表。在那里,因为我只想要与列表中的所有项目匹配的产品 – Harry 2014-09-13 09:57:16

+1

糟糕...您是对的,在这种情况下,并不像我希望的那么容易:)我会更新答案。 – Wolph 2014-09-13 10:00:54

+0

很好,这个工程。它会如何比较:\t species = Species.objects.filter(tags__description__in = tag_list).annotate(num_tags = Count('tags__description')).filter(num_tags = len(tag_list)) – Harry 2014-09-13 10:12:55

1

我想这样做的另一个方法是:

tag_list = request.GET.get('q').split(',') 
species = Species.objects.all().distinct() 
for tag in tag_list: 
    species = species.filter(tags__description=tag) 
else: 
    species = Species.objects.none()