243๐
Just restating what Tomasz said.
There are many examples of FOO__in=...
style filters in the many-to-many and many-to-one tests. Here is syntax for your specific problem:
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])
The double underscore (__) syntax is used all over the place when working with querysets.
54๐
Note that if the user may be in multiple zones used in the query, you may probably want to add .distinct()
. Otherwise you get one user multiple times:
users_in_zones = User.objects.filter(zones__in=[zone1, zone2, zone3]).distinct()
- [Django]-Django rest framework, use different serializers in the same ModelViewSet
- [Django]-Retrieving parameters from a URL
- [Django]-Django connection to postgres by docker-compose
11๐
another way to do this is by going through the intermediate table. Iโd express this within the Django ORM like this:
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'))
it would be nice if it didnโt need the .values('user')
specified, but Django (version 3.0.7) seems to need it.
the above code will end up generating SQL that looks something like:
SELECT * FROM users WHERE id IN (SELECT user_id FROM userzones WHERE zone_id IN (1,2,3))
which is nice because it doesnโt have any intermediate joins that could cause duplicate users to be returned
- [Django]-Django optional URL parameters
- [Django]-TypeError: data.forEach is not a function
- [Django]-How to change the name of a Django app?
2๐
You can also lookup simply by name, without __in
:
class Publication(models.Model):
...
class Article(models.Model):
publications = models.ManyToManyField(Publication)
Article.objects.filter(publications=1)
# or
Article.objects.filter(publications=p1)
Works with related_name
as well from my tests.
per Django docs
- [Django]-What is related_name used for?
- [Django]-Django Installed Apps Location
- [Django]-Django-allauth social account connect to existing account on login
1๐
I had a similar problem where some users ended with a free role and also a paid role, so I needed to select users that have two specific roles on the many to many field.
I did something like this, works like a charm
roles = [premium_role, default_role]
DiscordUser.objects.filter(guild=guild)
.annotate(freemium=Count('roles', filter=Q(roles__in=roles)))
.filter(freemium=2)
.values('id')
If you want this to be more dynamic, you can change this line with
.filter(freemium=len(roles))
- [Django]-How to check if ManyToMany field is not empty?
- [Django]-How to save pillow image object to Django ImageField?
- [Django]-Django custom management commands: AttributeError: 'module' object has no attribute 'Command'
0๐
You could use Q object if you have more complex query in the scenario like this question.
based on this question suppose you want to filter Users with specific id(e.g. 10) and filter Zones with the name that starts with โeuropeโ
query would be like this:
filtered_zone = Q(zones__in=Zone.objects.filter(name__startswith='europe')
result = User.objects.filter(Q(id=10) & Q(filtered_zone))
- [Django]-Using django-rest-interface
- [Django]-Creating a JSON response using Django and Python
- [Django]-Celery missed heartbeat (on_node_lost)