【发布时间】:2019-02-11 05:59:43
【问题描述】:
我无法弄清楚如何使用高级 Q 搜索来检索对象,任何可能完全以错误的方式接近它。
我认为在我尝试描述问题之前完全定义模型会更容易。我要解决的问题比我要在这里给出的示例稍微复杂一些,但那是因为我想更清楚地了解我正在尝试做的事情。
我这里有两个模型:
class Tag(models.Model):
name = models.CharField()
class Container(models.Model):
tags = models.ManyToManyField(Tag)
我能够检索到我想要的标签列表:
valid_tags = [Tag(x) for x in ['a', 'b', 'c', 'd']]
以下是一些容器的示例:
containers = [
Container(tags=[Tag(x) for x in ['a', 'b']),
Container(tags=[Tag(x) for x in ['b']),
Container(tags=[Tag(x) for x in ['a', 'b', 'c']),
Container(tags=[Tag(x) for x in ['e']),
Container(tags=[Tag(x) for x in ['a', 'e']),
]
我想要的查询输出是这样的:
valid_containers = [
Container(tags=[Tag(x) for x in ['a', 'b']),
Container(tags=[Tag(x) for x in ['b']),
Container(tags=[Tag(x) for x in ['a', 'b', 'c']),
]
所以,基本上我要做的是一个“内连接”类型的操作,它将返回所有标签都在 valid_tags 中的容器。
如果我运行以下代码,它会返回以下输出,其中包含标签不满足条件的容器。
Container.objects.filter(tags__in=valid_tags)
[
Container(tags=[Tag(x) for x in ['a', 'b']),
Container(tags=[Tag(x) for x in ['b']),
Container(tags=[Tag(x) for x in ['a', 'b', 'c']),
Container(tags=[Tag(x) for x in ['a', 'e']), # Not wanted
]
我也尝试过使用高级 Q 对象,类似于 .filter(tags__in=valid_tags).exclude(~Q(tags__in=valid_tags)),但是它只返回整个容器列表,这是我不想要的.
我什至不确定我在这里尝试实现的查询在 SQL 中是什么样的,所以我无法编写一个返回正确响应的原始查询,我也想避免编写原始 SQL , 如果可能的话。我不反对,但我希望能够使用 Django 内置的 DB 方法。
另外,不确定这是否相关,但我正在针对 Django 1.11 运行我的代码,并且无法升级到 Django 2;如果我正在寻找的功能有助于使这项工作在 Django 2 中而不是在 Django 1.11 中,我不确定我是否能够升级,所以我可能必须弄清楚 SQL 查询。
编辑:
我发现 annotate 支持 Q 查询。因此,我随后尝试注释 a) 容器中有效的标签或 b) 容器中 not 有效的标签的计数。我希望能够通过执行 .filter(bad_tag_count=0) 过滤掉 (b) 中的任何内容,但我下面的代码似乎只输出对象中的标签数量:
containers \
.annotate(
valid_tags=Count(Q(tags__in=valid_tags))
).annotate(
bad_tags=Count(~Q(tags__in=valid_tags)
)
问题是 .valid_tags 和 .bad_tags 都只是输出容器中包含的标签的数量。至于我在这个查询中做错了什么,我真的很茫然。
【问题讨论】:
-
stackoverflow.com/a/11025600/2897115。我不确定,但我认为 .filter(tags__in=valid_tags).exclude(~Q(tags__in=valid_tags)) w.r.t 以上链接可以提供帮助。
-
我认为这也是可行的,但不幸的是它只是返回,就好像我已经运行了 .all() 一样。