[django] 장고 ManyToMany 필터 ()

모델이 있습니다.

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

그것은 단순해야하지만 내 두뇌가 협조하지 않는 것 같습니다!



답변

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])

이중 밑줄 (__) 구문은 querysets 작업시 모든 곳에서 사용됩니다 .


답변

사용자가 쿼리에 사용 된 여러 영역에있는 경우 .distinct ()를 추가 할 수 있습니다. 그렇지 않으면 한 명의 사용자가 여러 번 나타납니다.

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


답변

이를 수행하는 또 다른 방법은 중간 테이블을 거치는 것입니다. 나는 이것을 장고 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')지정이 필요하지 않으면 좋을 것입니다 . 그러나 장고 (버전 3.0.7)에는 필요합니다.

위의 코드는 다음과 같은 SQL을 생성합니다.

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

중복 사용자가 반환 될 수있는 중간 조인이 없기 때문에 좋습니다.


답변