如何在 Django 中使用 Q.AND 限制多对多关系的查询

发布于 2024-10-15 12:20:01 字数 1945 浏览 3 评论 0原文

我想获取具有 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你如我软肋 2024-10-22 12:20:01

我什至不知道这种格式!

文档显示 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文