如何在Django中使用Q.AND限制ManyToMany关系的查询
我想获取所有同时拥有两个特定标签的图片,分别是'tag1'和'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 = Q()
来添加所有参数,使用qobj.add(Q(tag__name='tag1'), Q.AND)
。但是……接下来的查询没有返回任何结果:
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或tag2的图片。
看起来在AND
的情况下,它在查找app_tag_images表中同时拥有这两个标签的记录,但显然没有这样的记录,因为每一行只对应一个标签ID和一个图片ID。
有没有办法用Q来构建这个查询呢?
附注:如果需要更多代码细节,请告诉我。
编辑:
这是使用Q构建的查询的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
。
为了参考,使用连接filter的方法生成的查询(同样简化)如下:
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)
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'))
更新:
我在我的模型上测试了qobj.add()方法,使用多对多关系(m2m),在1.2.3版本上运行得很好。
你简化后的模型复制粘贴也能正常工作。
你确定你的查询应该返回一些结果吗?
标准的Q用法 Q(tag__name='tag1') & Q(tag__name='tag2')
能返回结果吗?
你能打印一下 myquery.query
吗?
让我们把问题缩小一下。