Django 多对多过滤器()

Posted

技术标签:

【中文标题】Django 多对多过滤器()【英文标题】:Django ManyToMany filter() 【发布时间】:2011-01-14 04:04:36 【问题描述】:

我有一个模型:

class Zone(models.Model):
    name = models.CharField(max_length=128)
    users = models.ManyToManyField(User, related_name='zones', null=True, blank=True)

我需要按照以下方式构建一个过滤器:

u = User.objects.filter(...zones contains a particular zone...)

它必须是用户的过滤器,并且必须是单个过滤器参数。原因是我正在构建一个 URL 查询字符串来过滤管理员用户更改列表:http://myserver/admin/auth/user/?zones=3

看起来应该很简单,但我的大脑不合作!

【问题讨论】:

我不确定我是否正确 - User.objects.filter(zones__id=<id>)User.objects.filter(zones__in=<id(s)>) 不适合这个吗? 没关系 :) BTW User.objects.filter(zones__in=<id(s)>) 应该是 User.objects.filter(zones__id__in=<id(s)>) 只是想指出任何谷歌搜索的人,它只有在设置了相关名称时才有效。 zone_set 不起作用,例如。浪费了半个小时的时间:-) 【参考方案1】:

只是重申 Tomasz 所说的话。

many-to-many 和many-to-one 测试中有很多FOO__in=... 样式过滤器的示例。这是针对您的特定问题的语法:

users_in_1zone = User.objects.filter(zones__id=<id1>)
# same thing but using in
users_in_1zone = User.objects.filter(zones__in=[<id1>])

# filtering on a few zones, by id
users_in_zones = User.objects.filter(zones__in=[<id1>, <id2>, <id3>])
# and by zone object (object gets converted to pk under the covers)
users_in_zones = User.objects.filter(zones__in=[zone1, zone2, zone3])

在使用querysets 时,到处都使用双下划线 (__) 语法。

【讨论】:

谢谢@maxm。更新了一些示例的更新链接。 双下划线(啊。比那个少了 3 小时) 您能否说一下,如果我希望位于一组区域中的用户不仅仅是其中任何一个,该怎么办?假设找到位于 zone1、zone3、.. 和 zone 10 中的用户 查看# filtering on a few zones, by id 之后的...__in 示例。那些显示过滤多个 ids/对象(在这种情况下)。只需传入您关心的 zone1、zone3 和 zone10 ids/objects。或根据需要添加第四个。 谢谢。我只过滤单个值,而不是包含单个值的数组。【参考方案2】:

请注意,如果用户可能在查询中使用的多个区域中,您可能需要添加.distinct()。否则你会多次获得一个用户:

users_in_zones = User.objects.filter(zones__in=[zone1, zone2, zone3]).distinct()

【讨论】:

【参考方案3】:

另一种方法是通过中间表。我会在 Django ORM 中这样表达:

UserZone = User.zones.through

# for a single zone
users_in_zone = User.objects.filter(
  id__in=UserZone.objects.filter(zone=zone1).values('user'))

# for multiple zones
users_in_zones = User.objects.filter(
  id__in=UserZone.objects.filter(zone__in=[zone1, zone2, zone3]).values('user'))

如果不需要指定 .values('user') 就好了,但 Django(版本 3.0.7)似乎需要它。

上面的代码最终会生成如下所示的 SQL:

SELECT * FROM users WHERE id IN (SELECT user_id FROM userzones WHERE zone_id IN (1,2,3))

这很好,因为它没有任何可能导致重复用户返回的中间连接

【讨论】:

嗨。这本身并不是一个答案。您应该添加评论或编辑 QB 的答案,而不是添加额外的部分答案。 是的 - 如果你想编辑你的答案,让它本身是完整的(除非你有足够的业力来编辑 QB 的答案?)那将是最好的选择。理想情况下,在 *** 上有“一个正确答案”。它通常不会那么顺利,但值得瞄准。 @AndyBaker 同意!回想起来,QB 的答案可能应该是对 istruble 答案的评论,而我认为我的答案足够独特,可以单独回答,但是嗯

以上是关于Django 多对多过滤器()的主要内容,如果未能解决你的问题,请参考以下文章

Django 多对多字段过滤器列表

Django如何过滤多对多字段中的对象,而不是原始查询集

Django 多对多交集过滤

Django Rest Framework(多对多字段上的 GET 过滤器)

过滤后更新 Django 的多对多

在Django中按关系字段过滤多对多关系