Django AND查询使用Q对象



给定我有一个Product模型和一对多ProductTag模型。

class Product(models.Model):
[...]

class ProductTag(models.Model):
product = models.ForeignKey(Product)
tag_value = models.CharField()
[...]

如果我有3个带有一些标签的产品:

  1. 产品A[TagA]
  2. 产品B[TagB]
  3. 产品C[TagB/TagC]

我想动态查询";产品";带有一些标签

  1. 此查询只返回";产品A";(如预期(
Product.objects.filter(Q(producttag__tag_value="TagA"))
  1. 此查询返回所有3个产品(如预期(
Product.objects.filter(
Q(producttag__tag_value="TagA") | Q(producttag__tag_value="TagB")
)
  1. 我希望下面的查询只返回"产品C">
Product.objects.filter(
Q(producttag__tag_value="TagB") & Q(producttag__tag_value="TagC")
)

但是我得到一个空的查询集。为什么查询#3不起作用?

使用__in查询也会返回错误的结果(如预期(

Product.objects.filter(producttag__tag_value__in=["TagB", "TagC"])

上面的查询同时返回ProductB/ProductC。

更新

我使用Q对象进行查找的原因是,查询基于来自API端点的用户输入。例如

  • "tag=TagA">
  • "tag=TagA AND tag=TagB">
  • "tag=TagA AND NOT tag=TagC">

所以我需要根据用户输入运行动态Django查询,而不能对某些查询进行硬编码。

以下查询工作:

qs1 = Product.objects.filter(Q(producttag__tag_value="TagB"))
qs2 = Product.objects.filter(Q(producttag__tag_value="TagC"))
queryset = qs1 & qs2

上面的查询只返回ProductC。

大致基于这个答案https://stackoverflow.com/a/33271387/1682844

查询#3有效地要求ProductTag.tag_value单行上同时等于TagBTagC,这显然是不可能的。这是SQL查询语法/模型的结果,您总是基于表的单行进行筛选。

我没有想到比链接EXISTS子句(仅适用于Django 3.x(更花哨、更具性能的东西:

rel_tag = ProductTag.objects.filter(product=OuterRef('pk'))
Product.objects.filter(
Exists(rel_tag.filter(tag_value="TagB")) & 
Exists(rel_tag.filter(tag_value="TagC"))
)

最新更新