Объект Django Q неправильно выстраивается в цепочку

Я делаю запрос к полю ManyToMany (теги). Значения берутся из списка:

tag_q = Q()

tag_list = ["work", "friends"]
for tag in tag_list:
    tag_q &= Q(tags__tag=tag)

Post.objects.filter(tag_q)

Когда у меня только одно значение, он работает безупречно, но когда складывается больше объектов, он всегда возвращает пустой queryset.

Я не использовал tags__tag__in=tag_list, потому что он возвращал любой пост, содержащий любой из тегов в списке тегов (фильтр OR), а мне нужен фильтр AND.

Это мои модели:

class Tag(models.Model):
    tag = models.CharField(max_length=19, choices=TagChoices.choices())

class Post(models.Model):
    tags = models.ManyToManyField(Tag, related_name='posts', blank=True)

Это объект Q, который передается в запросе фильтра:

(AND: ('tags__tag', 'work'), ('tags__tag', 'friends')

Вы не можете работать с таким Q объектом: фильтр - это экзистенциальный квантификатор, а не универсальный. Это означает, что вы ищете единственное Tag, которое имеет как tag имя work, так и friends в то же самое время.

Можно работать со списком тегов, а затем подсчитывать, совпадает ли количество Tag с количеством элементов для поиска, например:

tag_list = ['work', 'friends']

Post.objects.filter(tags__tag__in=tag_list).annotate(
    ntags=Count('tags')
).filter(ntags=len(set(tag_list))

начиная с , вы можете работать с .alias(…) [Django-doc] вместо .annotate(…) [Django-doc]:

tag_list = ['work', 'friends']

Post.objects.filter(tags__tag__in=tag_list).alias(
    ntags=Count('tags')
).filter(ntags=len(set(tag_list))
Вернуться на верх