I have this model in my code:
class Conversation(models.Model):
participants = models.ManyToManyField(User, related_name="message_participants")
and I need to filter this "Conversation" model objects by the "participants" many-to-many field. meaning: I have for example 3 User objects, so I want to retrieve the only "Conversation" objects that has this 3 Users in it's "participants" field.
I tried doing this:
def get_exist_conv_or_none(sender,recipients):
conv = Conversation.objects.filter(participants=sender)
for rec in recipients:
conv = conv.filter(participants=rec)
where sender is a User object and "recipients" is a list of User objects. it won't raise error but it gives me the wrong Object of Conversation. Thanks.
edit: A more recent try lead me to this:
def get_exist_conv_or_none(sender,recipients):
participants=recipients
participants.append(sender)
conv = Conversation.objects.filter(participants__in=participants)
return conv
which basically have the same problem. It yields Objects which has one or more of the "participants" on the list. but what Im looking for is exact match of the many-to-many object. Meaning, an Object with the exact "Users" on it's many-to-many relation.
edit 2: My last attempt. still, won't work.
def get_exist_conv_or_none(sender,recipients):
recipients.append(sender)
recipients = list(set(recipients))
conv = Conversation.objects.annotate(count=Count('participants')).filter(participants=recipients[0])
for participant in recipients[1:]:
conv.filter(participants=participant)
conv.filter(count=len(recipients))
return conv
Ok so I found the answer: In order to make an exact match I have to chain-filter the model and then make sure it has the exact number of arguments it needs to have, so that the many-to-many field will have in it all the objects needed and no more.
I will check for the objects number using annotation: ( https://docs.djangoproject.com/en/dev/topics/db/aggregation/ )
ended up with this code:
def get_exist_conv_or_none(recipients):
conv = Conversation.objects.annotate(count=Count('participants')).filter(participants=recipients[0])
for participant in recipients[1:]:
conv = conv.filter(participants=participant)
conv = conv.filter(count=len(recipients))
return conv