【问题标题】:Django .exclude() returns empty querysetDjango .exclude() 返回空查询集
【发布时间】:2021-11-30 01:57:10
【问题描述】:

我在创建 QuerySet 时遇到了 .exclude() 的问题。

我参与的模型是:

职业

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)

能力

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

当我创建查询集时:

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: &lt;QuerySet []&gt;.
我尝试了各种 tweeks,例如 .exclude(ability__id__in=[2, 23, 81, 86]).exclude(ability__ability_name__in=['Foo name', 'Bar name'],但都没有成功。

我是 Django 新手,所以如果这很明显,我也会感谢一些指示 在哪里可以阅读更多关于我的错误的信息。

【问题讨论】:

    标签: python python-3.x django


    【解决方案1】:

    由于AbilitymanyToManyField,每个profession.ability 对象将具有django.db.models.fields.related.ManyRelatedManager 而不是能力对象的直接列表。因此,如果您想获得排除具有特定 ID 能力的所有职业,您可以尝试更改您的查询

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

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

    filterexclude 的行为与 multi-valued relationships 不同。

    虽然没有找到有效解释我的答案的链接,但这里是讨论相关内容的文档中的链接

    向下滚动到note本节链接的一部分:https://docs.djangoproject.com/en/3.2/topics/db/queries/#spanning-multi-valued-relationships

    【讨论】:

    • 也许我并不清楚我想要达到什么,但我不想排除职业,而是我想获得一个具有许多能力而没有我的能力的特定职业'Acolyte'指出.exclude([2, ...]),但感谢您的回答
    • 是的,您获取特定职业“Acolyte”的过滤器保持不变,我指定的“排除”部分将满足您跳过您在列表中传递的 abilitiy_ids 的要求,无需 for 循环或任何类型迭代次数
    【解决方案2】:

    您的查询集适用于Profession 模型,因此当您编写queryset.exclude(ability__in=&lt;list_of_abilities&gt;) 时,您会得到一个查询集,其中排除了Profession(不是Ability)该能力在给定列表中的实例,即如果有与Profession 相关的Ability 在该列表中,该职业将被排除在外。相反,如果您首先获得 Profession 对象,然后在关系管理器上进行过滤,您将获得预期的结果:

    queryset = Profession.objects.filter(profession_name="Acolyte")
    
    for profession in queryset:
        print(profession.ability.exclude(id__in=[2, 23, 81, 86]))
    

    【讨论】:

    • 你的解释给了我方向感以及我做错了什么。但我不太了解您的循环实现。我想获得一个可以传递给视图的查询集。基本上我想要一个 SQL 等价于 SELECT 能力 FROM Profession WHERE professional_name='Acolyte' 和能力 NOT IN [2, 23, 81, 86]
    • @korni 您建议的 SQL 对于您的模型来说是错误的,ManyToManyField 创建了一个中间/直通模型(表),其中包含两个相关模型的外键(即,如果您想过滤你需要加入的能力)。此外,如果profession_name 应该是唯一的(如果您通过它来识别对象,理想情况下应该是唯一的),您可以简单地编写profession = Profession.objects.get(profession_name="Acolyte"),然后编写profession.ability.exclude(id__in=[2, 23, 81, 86])。该循环只是为了演示概念而无需假设。
    • 非常感谢,我将其标记为答案。所以我的主要错误是排除具有这些 ID 的职业,试图对 ManyToManyField 工作进行错误查询,最后如果我使用 .get 而不是 .filter 然后 .exclude 摆脱什么,它可以正常工作我不需要......很高兴你能为我澄清它:D
    猜你喜欢
    • 1970-01-01
    • 2018-12-01
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 2017-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多