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 多对多过滤器()的主要内容,如果未能解决你的问题,请参考以下文章