Django .exclude() возвращает пустой набор запросов

У меня проблема с .exclude() при создании QuerySet.

Мои модели:

Профессия

class Profession(models.Model):
    profession_name = models.CharField(max_length=20)
    equipment = models.ManyToManyField(Equipment, blank=True)
    ability = models.ManyToManyField(Ability, blank=True)
    skill = models.ManyToManyField(Skill, blank=True)
    skill_advanced = models.ManyToManyField(SkillAdvanced, blank=True)

Ability

class Ability(models.Model):
    ability_name = models.CharField(max_length=35)

Когда я создаю QuerySet с:

self.prof_abilities = Profession.objects.filter(profession_name="Acolyte").values('ability')

Я получаю:

<QuerySet [{'ability': 2}, {'ability': 69}, {'ability': 81}, {'ability': 86}, {'ability': 23}]>

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

self.prof_abilities = Profession.objects.filter(profession_name="Acolyte").exclude(ability__in=[2, 23, 81, 86]).values('ability')

Но результатом является пустой QuerySet: <QuerySet []>.
Я пробовал различные твики, такие как .exclude(ability__id__in=[2, 23, 81, 86]) или .exclude(ability__ability_name__in=['Foo name', 'Bar name'], но безуспешно.

Я новичок в Django, так что если это что-то очевидное, я был бы также признателен за некоторые указатели где можно прочитать больше о моей ошибке.

Ваш набор запросов предназначен для модели Profession, поэтому, когда вы пишете queryset.exclude(ability__in=<list_of_abilities>), вы получаете набор запросов, в котором вы исключаете Profession (не Ability) случаи, когда способность находится в заданном списке, т.е. если любая из Ability, связанных с Profession, находится в этом списке, эта профессия будет исключена. Вместо этого, если вы сначала получите объект Profession, а затем выполните фильтрацию по менеджеру отношений, вы получите ожидаемый результат:

queryset = Profession.objects.filter(profession_name="Acolyte")

for profession in queryset:
    print(profession.ability.exclude(id__in=[2, 23, 81, 86]))

Поскольку Ability является manyToManyField, каждый объект profession.ability будет иметь django.db.models.fields.related.ManyRelatedManager, а не прямой список объектов способностей. Поэтому, если вы хотите получить Все профессии, исключающие способности с определенными идентификаторами, вы можете попробовать изменить запрос с

на
self.prof_abilities = Profession.objects.filter(profession_name="Acolyte").exclude(ability__in=[2, 23, 81, 86]).values('ability')

to

self.prof_abilities = Profession.objects.filter(profession_name="Acolyte").exclude(ability__in=Ability.objects.filter(id__in=[2, 23, 81, 86])).values('ability')

filter и exclude ведут себя по-разному по отношению к multi-valued relationships.

Хотя я не нашел ссылки на достоверное объяснение моего ответа, вот ссылка из документации, в которой обсуждается что-то связанное

Прокрутите вниз до note части этой ссылки раздела: https://docs.djangoproject.com/en/3.2/topics/db/queries/#spanning-multi-valued-relationships

Вернуться на верх