Django ORM:为ManyToManyField动态添加多个条件

时间:2014-09-14 07:33:42

标签: django django-models orm

假设我们将Django模型定义如下:

class Tag(models.Model):
  name=models.CharField(unique=True,max_length=50)

class Article(models.Model):
  title=models.CharField(max_length=100)
  text=models.TextField() 
  tag = models.ManyToManyField(Tag)

我们有一个标签列表:

tag_list = ['tag1','tag2','tag3']

目标是选择包含tag_list所有标签的文章。这个question显示了一种在顺序添加过滤条件的情况下实现此目的的方法:

articles = Articles.objects.filter(Q(tag__name=tag_list[0])).filter(Q(tag__name=tag_list[1])).filter(Q(tag__name=tag_list[2]))

但我们需要动态添加条件。以下查询不起作用:

qlist=[]
for tag in tag_list:
  qlist.append(Q(tag__name=tag))
articles = Articles.objects.filter(reduce(operator.and_, qlist))

我最终查询了列表中至少有一个标签的文章,然后手动过滤查询结果:

qlist=[]
qlist.append(Q(tag__name__in=tag_list))
articles = Articles.objects.filter(reduce(operator.and_, qlist)).distinct()

for article in articles:
  article_tag_list=[]
  for tag in article.tag.all():
    article_tag_list.append(tag.name)
  if set(tag_list).issubset(set(article_tag_list)):
    ...

有没有办法动态添加ManyToManyField的查询条件?

1 个答案:

答案 0 :(得分:0)

试试这个:

q_objects = Q()
for tag in tag_list:
  q_objects &= Q(tag__name=tag)
articles = Articles.objects.filter(q_objects)

我上面使用了多次这种模式,它总是对我有用。

更新:虽然一般来说此方法有效,但它不适用于此问题。上面的代码要求所有条件对于单个相关对象都是真的。在这种情况下,这意味着必须有一个具有三个不同名称的单个标签,这显然是荒谬的。

这是最终为OP工作的代码:

for tag in tag_list:
    articles = articles.filter(tag__name=tag)

Django docs provide a detailed explanation将多个规则放在一个filter()中并将它们放在多个filter()中(当涉及查询多值关系时)之间的区别。