我无法弄清楚如何使用高级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']),
]
因此,基本上我想做的是“内部联接”类型的操作,它将返回所有标签都在有效标签中的容器。
如果我运行以下代码,它将返回以下输出,其中包含具有不满足条件的标记的容器。
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的内置数据库方法。
此外,不确定是否与此相关,但是我正在针对Django 1.11运行我的代码,并且无法升级到Django 2;如果我要寻找的功能有助于在Django 2中实现此功能,但在Django 1.11中却没有,我不确定是否能够升级,所以我可能必须找出SQL查询。
编辑:
我发现注释支持Q查询。因此,我然后尝试注释a)容器中有效的标签或b)容器中无效的标签的计数。我希望能够通过执行.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都只输出包含在容器中的标签的数量。就我在此查询中所做的错误而言,我真的很茫然。
答案 0 :(得分:0)
事实证明,我意识到我确实从错误的角度来解决问题。我的目标是找到所有具有满足有效标签条件的标签的容器。
解决方案很简单:
non_valid_tags = Tag.objects.exclude(id__in=valid_tags) # Apparently Django knows that if the query passed in is based on the object here, it will use the same field that is being queried so I don't need to do valid_tags.values_list('id', flat=True), although that might be a point to consider if the query ends up running for too long
valid_containers = Containers.objects.exclude(tags__in=non_valid_tags) # rows corresponding to [0, 1, 2]
虽然这不是我需要解决的全部问题,但这为我提供了充实查询的起点。