Подтвердить что ты не робот

Как фильтровать модель django по своим объектам во много-много поле (точное совпадение)?

У меня есть эта модель в моем коде:

class Conversation(models.Model):
    participants = models.ManyToManyField(User, related_name="message_participants")

и мне нужно отфильтровать этот объект модели "Разговор" полем "участники" "многие ко многим". значение: у меня есть, например, 3 пользовательских объекта, поэтому я хочу получить только объекты "Разговор", в которых есть 3 пользователя в этом поле "Участники".

Я попытался сделать это:

def get_exist_conv_or_none(sender,recipients):
    conv = Conversation.objects.filter(participants=sender)
    for rec in recipients:
        conv = conv.filter(participants=rec)

где отправитель является объектом User, а "получатели" - это список объектов пользователя. он не будет вызывать ошибки, но он дает мне неправильный Object of Conversation. Спасибо.

изменить: Более новая попытка привела меня к этому:

def get_exist_conv_or_none(sender,recipients):
    participants=recipients
    participants.append(sender)
    conv = Conversation.objects.filter(participants__in=participants)
    return conv

которые в основном имеют одинаковую проблему. Он дает объекты, в которых есть один или несколько "участников" в списке. но то, что я ищу, является точным соответствием объекта many-to-many. Значение, объект с точными "пользователями" на нем отношение "многие ко многим".

edit 2: Моя последняя попытка. все равно не будет работать.

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
4b9b3361

Ответ 1

Хорошо, поэтому я нашел ответ: Чтобы сделать точное совпадение, мне нужно связать фильтр с моделью, а затем убедиться, что она имеет точное количество аргументов, которые ей нужны, так что поле "многие ко многим" будет иметь в ней все требуемые объекты и не более.

Я проверю номер объекта с помощью аннотации: (https://docs.djangoproject.com/en/dev/topics/db/aggregation/)

закончил с этим кодом:

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

Ответ 2

Для быстрого поиска с использованием индекса базы данных я использую этот код:

class YandexWordstatQueue(models.Model):
    regions = models.ManyToManyField(YandexRegion)
    regions_cached = models.CharField(max_length=10000, editable=False, db_index=True)
    phrase = models.ForeignKey(SearchPhrase, db_index=True)
    tstamp = models.DateTimeField(auto_now_add=True)

class YandexWordstatRecord(models.Model):
    regions = models.ManyToManyField(YandexRegion)
    regions_cached = models.CharField(max_length=10000, editable=False, db_index=True)
    phrase = models.ForeignKey(SearchPhrase, db_index=True)
    Shows = models.IntegerField()
    date = models.DateField(auto_now_add=True)

@receiver(m2m_changed, sender=YandexWordstatRecord.regions.through)
@receiver(m2m_changed, sender=YandexWordstatQueue.regions.through)
def yandexwordstat_regions_changed(sender, **kwargs):
    if kwargs.get('action') in ['post_add', 'post_remove']:
        instance = kwargs.get('instance')
        l = list(instance.regions.values_list('RegionID', flat=True))
        l.sort()
        instance.regions_cached = json.dumps(l)
        instance.save()

Это добавляет накладные расходы при сохранении, но теперь я могу выполнить быстрый фильтр с помощью этого фрагмента:

region_ids = [1, 2, 3] # or list(some_queryset.values_list(...))
region_ids.sort()
regions_cahed = json.dumps(region_ids)
YandexWordstatQueue.objects.filter(regions_cached=regions_cached)