class Keyword(models.Model):
keyword = models.CharField(max_length=100, unique=True)
class Item(models.Model):
keywords = models.ManyToManyField(Keyword)
如何动态创建以下内容?即我可以添加'c'
items = Item.objects.filter(keywords__keyword__exact = 'a')
.filter(keywords__keyword__exact = 'b')
我尝试过构建Q对象:
tags = ['a', 'b']
queries = [Q(keywords__keyword__exact=tag) for tag in tags]
query = Q()
for q in queries:
query &= q
items = Item.objects.filter(query)
但是这似乎使用像keyword = a & keyword = b
之类的查询,它总是返回空。
答案 0 :(得分:3)
对于这个问题,您的解决方案远远过于设计。
编辑:我没有意识到这个问题是在关键字之间寻找逻辑AND而不是逻辑OR。我已经用两个选项更新了这个答案。
当您想要检索包含任何列出的关键字的项目时,这非常有用
Django提供a very good API for Queryset filtering,它为我们提供了一种更简单的方法来创建您想要的行为。没有必要为此创建一个令人困惑的Q对象解决方案。我将使用您的上一个代码段来解释更直接的解决方案,并使用Queryset查找关键字in
(here's a link to the docs)。
tags = ['a', 'b']
# Removed the complex Q object definition.
items = Item.objects.filter(keywords__keyword__in=tags)
这应该为您提供一个结果Queryset,其中包含与关键字对象关联的Item对象,该关键字对象包含与列表tags
中的任何值匹配的关键字。例如:
tags = ['a', 'b']
keyword_one = Keyword.objects.create(keyword='a')
keyword_two = Keyword.objects.create(keyword='b')
keyword_three = Keyword.objects.create(keyword='c')
item_one = Item.objects.create()
item_one.keywords.add(keyword_one)
item_one.save()
item_two = Item.objects.create()
item_two.keywords.add(keyword_two)
item_two.save()
item_three = Item.objects.create()
item_three.keywords.add(keyword_three)
item_three.save()
# items will only contain item_one and item_two, but not item_three.
tag_items = Item.objects.filter(keywords__keyword__in=tags)
当您想要检索列出了所有关键字的项目时,这非常有用
Here's an approach which will serve our purposes
相关代码示例:
tags = ['a', 'b']
items_with_one_of_tags = Item.objects.filter(keywords__keyword__in=tags)
items_with_all_of_tags = items_with_one_of_tags.annotate(number_of_keywords=Count('keywords')).filter(number_of_keywords=len(tags))
此方法的工作方式是在Queryset中创建一个聚合列,其中包含与每个Item对象关联的关键字对象的数量,这些对象与至少一个关键字对象相关联。然后,此聚合列(名为number_of_keywords
)仅用于过滤列出具有确切关键字数量的Item对象。
通过此方法,Annotation方法可以删除具有某些关键字的Item对象。请注意,这不会返回具有列出的关键字且仅列出关键字的Item对象集。仅保证返回的Item对象将具有每个关键字。有an example in that linked discussion thread使用嵌套查询可以排除Item对象,除了列出的关键字之外还有额外的关键字。