Django: запрашивает два поля ManyToMany в одной и той же модели

Даны следующие модели:

class Color(models.Model):
    name = models.CharField()

class Child(models.Model):
    fave_colors = models.ManyToManyField(Color)
    tshirt_colors = models.ManyToManyField(Color)

Как бы я построил запрос, чтобы найти детей, футболки которых в точности соответствуют их любимым цветам т.е.

lucky_kids = Child.objects.filter(
    fave_colors__exact=tshirt_colors
) # obvious but not valid query

Мы можем подсчитать количество (различных) fave_colors, а затем подсчитать количество fave_colors, которые также отображаются в tshirt_colors, и проверить, совпадают ли они, с помощью:

from django.db.models import Count, F, Q

Child.objects.alias(
    nfav=Count('fave_colors', distinct=True),
    ntshirt=Count('tshirt_colors', distinct=True),
    nfav_tshirt=Count(
        'fave_colors', filter=Q(fave_colors__kid_tshirt=F('pk')), distinct=True
    ),
).filter(nfav=F('nfav_tshirt'), ntshirt=F('nfav'))

Размышляя о поведении __in Я понял, что это вернет список детей, у которых на футболках есть хотя бы один любимый цвет:

Child.objects.filter(Q(fave_colors__in=F('tshirt_colors'))).distinct()

Отрицание (~) запрос фильтра выдает результат, противоположный тому, который я ищу, т.е. набор всех детей, у которых нет точно таких же своих любимых футболок:

Child.objects.filter(~Q(fave_colors__in=F('tshirt_colors'))).distinct()

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

unlucky_kids = Child.objects.filter(
    ~Q(fave_colors__in=F('tshirt_colors'))).distinct()

lucky_kids = Child.objects.all().difference.(unlucky_kids)
Вернуться на верх