如何在 Django 中使用 Q.AND 限制多对多关系的查询
我想获取具有 2 个特定标签“tag1”AND
“tag2”的所有图像。我的简化模型:
class Image(models.Model):
title = models.CharField(max_length=100)
class Tag(models.Model):
name = models.CharField(max_length=64, unique=True)
images = models.ManyToManyField(Image, null=True, blank=True)
连接 filter
有效:
query = Image.objects.filter(tag__name='tag1').filter(tag__name='tag2')
但是,我认为我可以使用 Django 中的 Q 对象来做到这一点。我正在构建一个复杂的查询,因此使用 Q 会更简单。我使用 qobj.add(Q(tag__name='tag1'), Q.AND)
将所有参数添加到 qobj = Q()
中。但是...以下内容什么也检索不到:
qobj = Q()
qobj.add(Q(tag__name='tag1'), Q.AND)
qobj.add(Q(tag__name='tag2'), Q.AND)
query = Image.objects.filter(qobj)
在上面的代码中使用 OR
连接器时,一切都按预期工作,正确返回具有 tag1 OR
tag2 的图像。
似乎在 AND
情况下,它正在寻找 app_tag_images 中具有两个标签的行,这显然不存在,因为每一行只有一个 image_id 的 tag_id 。
有没有办法用 Q 构建这个查询?
ps:如果需要更多代码细节,请告诉我。
编辑:
这是带有 Q 的查询的 que sql 查询(为了清楚起见,我清理了大多数 SELECT
列):
SELECT "meta_image"."id", "meta_image"."title"
FROM "meta_image"
INNER JOIN "meta_tag_images" ON ("meta_image"."id" = "meta_tag_images"."image_id")
INNER JOIN "meta_tag" ON ("meta_tag_images"."tag_id" = "meta_tag"."id")
WHERE ("meta_tag"."name" = tag1 AND "meta_tag"."name" = tag2)
OR
查询与上面相同(将 AND
替换为 OR
)。
仅供参考,使用过滤器连接的工作方法打印此查询(也经过简化):
SELECT "meta_image"."id", "meta_image"."title"
FROM "meta_image"
INNER JOIN "meta_tag_images" ON ("meta_image"."id" = "meta_tag_images"."image_id")
INNER JOIN "meta_tag" ON ("meta_tag_images"."tag_id" = "meta_tag"."id")
INNER JOIN "meta_tag_images" T4 ON ("meta_image"."id" = T4."image_id")
INNER JOIN "meta_tag" T5 ON (T4."tag_id" = T5."id")
WHERE ("meta_tag"."name" = tag1 AND T5."name" = tag2)
I want to get all images that have 2 specific tags, 'tag1' AND
'tag2'. My simplified models:
class Image(models.Model):
title = models.CharField(max_length=100)
class Tag(models.Model):
name = models.CharField(max_length=64, unique=True)
images = models.ManyToManyField(Image, null=True, blank=True)
Concatenating filter
works:
query = Image.objects.filter(tag__name='tag1').filter(tag__name='tag2')
However, I thought I could do it using the Q object from Django. I'm building a complex query, so using Q would be more straightforward. I'm adding all parameters to a qobj = Q()
using qobj.add(Q(tag__name='tag1'), Q.AND)
. But... the following retrieves nothing:
qobj = Q()
qobj.add(Q(tag__name='tag1'), Q.AND)
qobj.add(Q(tag__name='tag2'), Q.AND)
query = Image.objects.filter(qobj)
Everything works as expected when using OR
connector in the code above, returning correctly images that have tag1 OR
tag2.
It seems that in the AND
case it is looking for a row in app_tag_images with both tags, which is obviously absent, since each row has only one tag_id for a image_id.
Is there a way to build this query with Q?
ps: let me know if more details of the code are needed.
edit:
Here is que sql query of the query with Q (I cleaned most SELECT
columns for clarity):
SELECT "meta_image"."id", "meta_image"."title"
FROM "meta_image"
INNER JOIN "meta_tag_images" ON ("meta_image"."id" = "meta_tag_images"."image_id")
INNER JOIN "meta_tag" ON ("meta_tag_images"."tag_id" = "meta_tag"."id")
WHERE ("meta_tag"."name" = tag1 AND "meta_tag"."name" = tag2)
OR
query is identical as above (replacing AND
by OR
).
Just for reference, the working method using filter concatenating prints this query (also simplified):
SELECT "meta_image"."id", "meta_image"."title"
FROM "meta_image"
INNER JOIN "meta_tag_images" ON ("meta_image"."id" = "meta_tag_images"."image_id")
INNER JOIN "meta_tag" ON ("meta_tag_images"."tag_id" = "meta_tag"."id")
INNER JOIN "meta_tag_images" T4 ON ("meta_image"."id" = T4."image_id")
INNER JOIN "meta_tag" T5 ON (T4."tag_id" = T5."id")
WHERE ("meta_tag"."name" = tag1 AND T5."name" = tag2)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我什至不知道这种格式!
文档显示 Q 对象用法的方式有什么问题? http://docs.djangoproject。 com/en/dev/topics/db/queries/#complex-lookups-with-q-objects
Image.objects.filter(Q(tag__name='tag1') & Q(tag__name=' tag2'))
更新:
我使用 m2m 在我的模型上测试了 qobj.add() 方法,它在 1.2.3 上运行良好,
复制和粘贴简化模型也运行良好。
您确定您的查询应该返回一些内容吗?
标准 Q 用法是否
Q(tag__name='tag1') & Q(tag__name='tag2')
返回结果?您也可以打印
myquery.query
吗?让我们缩小范围。
I wasn't even aware of that format!
What's wrong with the way the docs show Q object usage? http://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects
Image.objects.filter(Q(tag__name='tag1') & Q(tag__name='tag2'))
UPDATE:
I tested the qobj.add() method on my model with m2m and it works fine on 1.2.3
It also works fine copy and pasting your simplified model.
Are you sure your query is supposed to return something?
Does the standard Q usage
Q(tag__name='tag1') & Q(tag__name='tag2')
return results?Can you print
myquery.query
as well?Let's narrow this down.