假设我有以下型号

class Photo(models.Model):
    tags = models.ManyToManyField(Tag)

class Tag(models.Model):
    name = models.CharField(max_length=50)

在一个视图中,我有一个名为categories的活动过滤器列表. 我想要过滤的照片对象,其中所有的标签都在categories%.

我试过了:

Photo.objects.filter(tags__name__in=categories)

但这在类别上与any个项目匹配,而不是all个项目.

因此,如果分类是[‘假日’,‘夏季’],我想要既有假日标签又有夏季标签的照片.

这是否可以做到呢?

推荐答案

Summary:

一种 Select 是,正如jic和sGallen在 comments 中所建议的那样, for each 类别增加.filter()个.每增加filter个连接就会添加更多连接,这对于较小的类别集应该不是问题.

这是aggregationapproach.对于较大的类别集,此查询会更短,而且可能更快.

您也可以 Select 使用custom queries.


Some examples

测试设置:

class Photo(models.Model):
    tags = models.ManyToManyField('Tag')

class Tag(models.Model):
    name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.name

In [2]: t1 = Tag.objects.create(name='holiday')
In [3]: t2 = Tag.objects.create(name='summer')
In [4]: p = Photo.objects.create()
In [5]: p.tags.add(t1)
In [6]: p.tags.add(t2)
In [7]: p.tags.all()
Out[7]: [<Tag: holiday>, <Tag: summer>]

Using chained filters approach:

In [8]: Photo.objects.filter(tags=t1).filter(tags=t2)
Out[8]: [<Photo: Photo object>]

结果查询:

In [17]: print Photo.objects.filter(tags=t1).filter(tags=t2).query
SELECT "test_photo"."id"
FROM "test_photo"
INNER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
INNER JOIN "test_photo_tags" T4 ON ("test_photo"."id" = T4."photo_id")
WHERE ("test_photo_tags"."tag_id" = 3  AND T4."tag_id" = 4 )

注意,每filter个向查询添加JOINS个以上.

Using annotation approach:

In [29]: from django.db.models import Count
In [30]: Photo.objects.filter(tags__in=[t1, t2]).annotate(num_tags=Count('tags')).filter(num_tags=2)
Out[30]: [<Photo: Photo object>]

结果查询:

In [32]: print Photo.objects.filter(tags__in=[t1, t2]).annotate(num_tags=Count('tags')).filter(num_tags=2).query
SELECT "test_photo"."id", COUNT("test_photo_tags"."tag_id") AS "num_tags"
FROM "test_photo"
LEFT OUTER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
WHERE ("test_photo_tags"."tag_id" IN (3, 4))
GROUP BY "test_photo"."id", "test_photo"."id"
HAVING COUNT("test_photo_tags"."tag_id") = 2

ANDed Q objects would not work:

In [9]: from django.db.models import Q
In [10]: Photo.objects.filter(Q(tags__name='holiday') & Q(tags__name='summer'))
Out[10]: []
In [11]: from operator import and_
In [12]: Photo.objects.filter(reduce(and_, [Q(tags__name='holiday'), Q(tags__name='summer')]))
Out[12]: []

结果查询:

In [25]: print Photo.objects.filter(Q(tags__name='holiday') & Q(tags__name='summer')).query
SELECT "test_photo"."id"
FROM "test_photo"
INNER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
INNER JOIN "test_tag" ON ("test_photo_tags"."tag_id" = "test_tag"."id")
WHERE ("test_tag"."name" = holiday  AND "test_tag"."name" = summer )

Django相关问答推荐

如何在Django表单中传递self.请求数据?

无法将关键字average_rating解析为字段

Django REST序列化程序TO_REATION失败

如何使用邮箱确认码创建django注册

在 Serverless + Lambda + API Gateway HTTP API 上运行的 Django 应用程序正在重写链接以使用默认前缀

Django ORM:子查询上的文本聚合器

Django 转储数据将附加数据添加到 json 导出

如何将 ManyToManyField 与另一个 ManyToManyField 进行比较

超级用户在基于类的视图中进行身份验证

如何从不是 django 元素文件夹的文件夹中运行 gunicorn

在 Django 管理屏幕中删除添加另一个

Django BigInteger自动增量字段作为主键?

使用 lambda 作为属性的默认值时,Django 1.7.1 Makemigrations 失败

django 模板 if 或语句

has_object_permission 和 has_permission 有什么区别?

在 docker 容器中创建 django 超级用户而不输入密码

我应该如何在我的模型中使用 DurationField?

Django Rest 框架 ImageField

如何在 django 2.0 admin 中使用 allow_tags?

如何在 Django 中创建一个非空的 CharField?