Django ManyToMany过滤器()

And*_*ker 111 django django-models

我有一个模特:

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

我需要构建一个过滤器:

u = User.objects.filter(...zones contains a particular zone...)
Run Code Online (Sandbox Code Playgroud)

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

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

ist*_*ble 131

重申Tomasz所说的话.

多对多多对一测试中有许多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])
Run Code Online (Sandbox Code Playgroud)

有工作时,双下划线(__)语法用于所有的地方查询集.

  • 双下划线(对那个人来说损失了3个小时) (6认同)
  • 如果我想按精确的区域列表进行过滤该怎么办?就像 `exact_zones = User.objects.filter(zones=[1,2])` 我收到错误说它应该是 ID 而不是列表。但我需要这些确切的区域。 (2认同)

小智 26

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

users_in_zones = User.objects.filter(zones__in=[zone1, zone2, zone3]).distinct()
Run Code Online (Sandbox Code Playgroud)


Sam*_*son 11

另一种方法是通过中间表。我会在 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'))
Run Code Online (Sandbox Code Playgroud)

如果不需要指定就好了.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))
Run Code Online (Sandbox Code Playgroud)

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