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)