2017-08-13 1 views
0

J'utilise Django + Postgres et ce modèle:Comment filtrer ManyToManyField avec distinct?

class Room(models.Model): 
    users = models.ManyToManyField(settings.AUTH_USER_MODEL) 
    type = models.IntegerField(default=1) 

room table de données exemple:

____________________ 
| id  | type | 
|-------------------- 
| 1  | 1  | 
| 2  | 1  | 
| 3  | 2  | 
... 

room_users table de données exemple:

____________________ 
| room_id | user_id | 
|-------------------- 
| 1  | 100  | 
| 1  | 101  | 
| 2  | 100  | 
| 2  | 102  | 
| 3  | 103  | 
... 

Q: Comment obtenez room_idseulement 2 utilisateurs participent et la salle a type=1? Comme vous le savez, ManyToManyField crée automatiquement la table room_users. Voici un exemple de code si j'accéder directement à room_users, mais je ne sais pas comment (room_users n'a pas présenté dans django comme modèle en raison de ManyToManyField):

user_id_1 = 100 
user_id_2 = 101  
rooms = Room.objects.filter(users__in=[user_id_1, user_id_2], type=1).distinct("users__room_id").values_list("users__room_id", flat=True) 
# result must me rooms[0].id = 1, len(rooms) = 1 

Pour cette erreur de cas est la suivante:

django.core.exceptions.FieldError: Cannot resolve keyword 'room_id' into field. Choices are: date_joined, email, first_name, groups, id, is_active, is_staff, is_superuser, last_login, last_name, logentry, password, user_permissions, username 
+0

Je compris que vous voulez trouver le numéro de pièce où user1 et user2 ensemble ont droit? pourquoi ne faites-vous pas une requête comme 'Room.objects.filter (users__in = [user_id_1, user_id_2], tapez = 1) .distinct (" id "). values_list (" id ", flat = true)'? – Jayground

+0

Parce qu'il imprime mauvaise réponse. Il imprime tous les identifiants de pièce où trouve 'user_id_1' et' user_id_2' – sirjay

Répondre

0
rooms = Room.objects.filter(type=1) 
rooms = rooms.annotate(num_guests=Count('users')).filter(num_guests=2) 

j'ai ajouté une autre pièce de type 1 à tester, et un utilisateur séjourné dans la chambre avec la coquille finale obtenir 2, je préfère le faire en 2 parties

To get the detail, iterate over the queryset

+0

merci de répondre. où sont 'user_id_1' et' user_id_2' dans votre réponse? – sirjay

+0

J'ai mis à jour l'exemple. Votre critère était: get room_id où seulement 2 utilisateurs sont participants et room a type = 1. Allez-vous coder en dur dans les identifiants utilisateur pour filtrer à chaque fois? – diek

+0

@sirjay avez-vous essayé la révision? – diek

1

Je ne sais pas si c'est la meilleure façon de résoudre votre problème quand vous considérez la performance.

Mon idée

user1 = User.objects.get(id=100).room_set.all() 
user2 = User.objects.get(id=101).room_set.all() 

same_room = user1.intersection(user2) 

chèque Django manual about intersection si vous avez besoin