Получить модели в Django, которые имеют все значения в поле ManyToMany (И-query, обратный поиск не допускается)

#django #python-2.7

#django #python-2.7

Вопрос:

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

 class VariantTag(models.Model):
    saved_variants = models.ManyToManyField('SavedVariant')
  

Мне нужно получить все VariantTag модели, у которых есть ManyToMany поле saved_variants с точными идентификаторами, скажем (250, 251) , не больше, не меньше. По характеру кода, с которым я имею дело, я не могу выполнить обратный поиск _set . Итак, я ищу запрос (или несколько запросов дополнительная фильтрация кода python), который приведет меня туда, но таким образом:

 query = Q(...)
tag_queryset = VariantTag.objects.filter(query)
  

Как этого можно достичь?

Я, вероятно, должен подчеркнуть: предоставленные сохраненные варианты (например (250, 251) , должно быть AND — ed, не OR — ed.

Комментарии:

1. Почему релевантен обратный поиск? Ах, вы действительно хотите сделать это с другой стороны, но думаете, что не можете?

2. Idk, я могу просто ошибаться. Я хочу на самом деле фильтровать saved_variants__in= , как указано в ответе по внешним ключам и другим параметрам. Если я добавляю какие-либо дополнительные параметры в saved_variants__in запрос, это всегда ничего мне не дает.

3. Допустим, у SavedVariant есть поле «name». Если вы хотите, чтобы все теги вариантов, которые сохранили варианты с полем имени, равным «Bob», вы делаете VariantTag.objects.filter(saved_variants__name='Bob') . Но, возможно, это не то, что вы ищете.

Ответ №1:

Используйте in поиск

 tag_queryset = VariantTag.objects.filter(saved_variants__in=[250,251])  

Комментарии:

1. Можно ли добавить дополнительное свойство для фильтрации, например VariantTag.objects.filter(name=..., saved_variants__in=[250,251]) ?

2. Да, это возможно

3. Так или иначе, не работает, пока я использую параметр модели внешнего ключа. Например.: VariantTag.objects.filter(variant_tag_type__name='Name_of_the_tag', saved_variants__in=saved_variant_ids) . Но я проверил DB, он есть.

4. Я предполагаю, что это проблема дополнительного соединения, которое мне нужно сделать для получения дополнительных параметров. Возможно, будет задан новый вопрос. Это похоже на VariantTag -> VariantTagType . Последний содержит все параметры.

5. Я не думаю, что это дает AND операцию, но я думаю, что это так OR , верно? Я решил проблему с моим внешним ключом, и теперь я вижу, что это решение, похоже, не работает: оно возвращает также модели, в которых saved_variants есть только одно значение, например 250 , но это не работает для меня, как указано в вопросе.

Ответ №2:

До сих пор я смог добиться AND результата с помощью следующего кода:

 tag_ids = VariantTag.objects.filter(variant_tag_type__name=tag_data['tag'],
                                        saved_variants__in=saved_variant_ids).values_list('id', flat=True).distinct()
for tag_id in tag_ids:
    saved_variants = list(VariantTag.objects.get(id=tag_id).saved_variants.all().values_list('id', flat=True))
    if all(s in saved_variant_ids for s in saved_variants) and len(saved_variants) == len(saved_variant_ids):
        return VariantTag.objects.get(id=tag_id)
  

Итак, я делаю следующее:

  1. Получение OR — результата
  2. Перебор результирующих идентификаторов извлеченной модели и для каждого из них получение всех идентификаторов ManyToMany поля
  3. Проверка, все ли полученные идентификаторы ManyToMany поля находятся в списке требуемых идентификаторов ( saved_variant_ids )
  4. Если да — получить модель по идентификатору: VariantTag.objects.get(id=tag_id)

В моем случае будет только одна такая модель с требуемыми идентификаторами в ManyToMany поле. Если это не так для вас — просто добавьте идентификаторы модели (в моем случае tag_id ) в список — затем сделайте запрос для всех из них.

Если у кого-нибудь есть более краткий способ выполнения AND ManyToMany запроса код, было бы интересно посмотреть.