Django filter queryset __in только для элементов в списке - PullRequest
2 голосов
/ 27 мая 2020

Модели:

class Tag(models.Model):
    name = models.CharField(max_length=20)


class Post(models.Model):
    tags = models.ManyToManyField(Tag)
    title = models.CharField(max_length=20)

Данные:

a_post=Post.objects.create(title='a')
ab_post=Post.objects.create(title='ab')
ac_post=Post.objects.create(title='ac')
a_tag=a_post.tags.create(name='a')
ab_post.tags.add(a_tag)
b_tag=ab_post.tags.create(name='b')
ac_post.tags.add(a_tag)
ac_post=ac_post.tags.create(name='c')

Я хочу запросить все сообщения только с тегами в списке. Сообщения с другими тегами не возвращаются. Вот такой код:

Post.objects.filter(tags__name__only_in=['a','b']).all()

должен вернуть [a_post, ab_post].

Я уже читал this . Цепные фильтры не помогут. Есть идеи?

1 Ответ

1 голос
/ 27 мая 2020

Вы можете проверить, совпадает ли количество Tag s, удовлетворяющих предикату, с общим количеством тегов:

from django.db.models import Count, Q

Post.objects.annotate(
    ntags=Count('tags')
).filter(
    ntags=Count('tags', <b>filter=Q(tags__name__in=['a', 'b'])</b>),
    ntags__gt=0
)

Таким образом, первый фильтр проверяет, соответствует ли общее количество связанных тегов то же, что и количество тегов с именем 'a' или 'b'. Если число другое, значит, мы знаем, что существует тег с другим именем.

Второй фильтр проверяет, больше ли количество тегов нуля, чтобы исключить совпадения без тегов.

...