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