Фильтрация (сохранение People
, которые воспроизводят все данные Sport
с)
Решение не тривиально.Однако если вы можете рассчитать длину списка, то это можно сделать, рассчитав число перекрытий между списком видов спорта и sports
a Person
воспроизведений.:
from django.db.models import <b>Count</b>
sports_list = [1, 2, 3]
Person.objects.filter(
<b>sports__in=sports_list</b>
).annotate(
<b>overlap=Count('sports')</b>
).filter(<b>overlap=len(sports_list)</b>)
Так что, если число видов спорта Person
в sports_list
равно количеству элементов в sports_list
, то мы знаем, что человек играет все эти виды спорта.
неуникальные Sport
s в sport_list
Обратите внимание, что sport_lists
должен содержать уникальных Sport
объектов (илиидентификаторы).Однако вы можете построить набор из sports
, например:
# in case a sport can occur *multiple times in the list
from django.db.models import Count
sports<b>_set</b> = <b>set(</b>[1, 2, 3, 2, 3, 3]<b>)</b>
Person.objects.filter(
sports__in=sports<b>_set</b>
).annotate(
overlap=Count('sports')
).filter(overlap=len(sports_<b>_set</b>))
SQL-запрос
За шторами мы создадим запрос наподобие:
SELECT `person`.*
FROM `person`
INNER JOIN `person_sport` ON `person`.`id` = `person_sport`.`person_id`
WHERE `person_sport`.`sport_id` IN (1, 2, 3)
GROUP BY `person`.`id`
HAVING COUNT(`person_sport`.`sport_id`) = 3
Исключая (сохраняя People
, которые не воспроизводят все учитывая Sport
с)
Возможно, проблема связана с исключить тех лиц: лиц, которые занимаются всеми указанными видами спорта.Мы можем сделать это также, но тогда может возникнуть проблема: люди, которые вообще не занимаются спортом, также будут исключены, так как первый .filter(..)
удалит этих людей.Однако мы можем немного изменить код, чтобы они также были включены:
# opposite problem: excluding those people
from django.db.models import <b>Q,</b> Count
sports<b>_set</b> = <b>set(</b>[1, 2, 3, 2, 3, 3]<b>)</b>
Person.objects.filter(
<b>Q(</b>sports__in=sports_set<b>) | Q(sports__isnull=True)</b>
).annotate(
overlap=Count('sports')
)<b>.exclude</b>(overlap=len(sports__set))