如何在Django查询集过滤中执行不相等?

在Django模型QuerySets中,我看到比较值有__gt__lt,但是有__ne!=不等于)吗?我想使用不等于过滤掉。例如,对于

Model:bool a;int x;

我想做

results = Model.objects.exclude(a=True, x!=5)

!=不是正确的语法。我也尝试了__ne

我最终使用:

results = Model.objects.exclude(a=True, x__lt=5).exclude(a=True, x__gt=5)
606225 次浏览

最后一段代码将排除x!=5且a为True的所有对象。试试这个:

results = Model.objects.filter(a=False, x=5)

请记住,上面一行中的=符号将False分配给参数a,将数字5分配给参数x。它不是检查是否相等。因此,在查询调用中实际上没有任何方法使用!=符号。

您可以为此使用q对象。它们可以使用~运算符否定并像普通的Python表达式一样组合:

from myapp.models import Entryfrom django.db.models import Q
Entry.objects.filter(~Q(id=3))

将返回所有条目,但以3作为ID的条目除外:

[<Entry: Entry object>, <Entry: Entry object>, <Entry: Entry object>, ...]

查询中的field=value语法是field__exact=value的简写。也就是说Django将查询运算符放在标识符的查询字段上。Django支持以下运算符:

exactiexactcontainsicontainsingtgteltltestartswithistartswithendswithiendswithrange
dateyeariso_yearmonthdayweekweek_dayiso_week_dayquartertimehourminutesecond
isnullregexiregex

我确信通过将这些与Q对象组合为戴夫·沃格特建议并使用filter()exclude()作为杰森·贝克建议,您将获得几乎任何可能的查询所需的确切内容。

您的查询似乎有双重否定,您想排除x不是5的所有行,换句话说,您想包含x 5的所有行。我相信这会起作用:

results = Model.objects.filter(x=5).exclude(a=True)

要回答您的特定问题,没有“不等于”字段查找,但这可能是因为Django同时提供filterexclude方法,因此您可以随时切换逻辑以获得所需的结果。

虽然您可以使用=__gt__gte__lt__lte过滤模型,但不能使用ne!=。但是,您可以使用Q对象实现更好的过滤。

您可以避免链接QuerySet.filter()QuerySet.exclude(),并使用:

from django.db.models import Qobject_list = QuerySet.filter(~Q(field='not wanted'), field='wanted')

创建自定义查找很容易,Django的官方留档中有__ne查找示例。

您需要首先创建查找本身:

from django.db.models import Lookup
class NotEqual(Lookup):lookup_name = 'ne'
def as_sql(self, compiler, connection):lhs, lhs_params = self.process_lhs(compiler, connection)rhs, rhs_params = self.process_rhs(compiler, connection)params = lhs_params + rhs_paramsreturn '%s <> %s' % (lhs, rhs), params

然后你需要注册它:

from django.db.models import FieldField.register_lookup(NotEqual)

现在您可以在查询中使用__ne查找,如下所示:

results = Model.objects.exclude(a=True, x__ne=5)

你应该像这样使用filterexclude

results = Model.objects.exclude(a=true).filter(x=5)

有三种选择:

  1. 链#0和#1

    results = Model.objects.exclude(a=True).filter(x=5)
  2. 使用#0对象#1操作员

    from django.db.models import Qobject_list = QuerySet.filter(~Q(a=True), x=5)
  3. 注册一个自定义查找函数

    from django.db.models import Lookupfrom django.db.models import Field
    @Field.register_lookupclass NotEqual(Lookup):lookup_name = 'ne'
    def as_sql(self, compiler, connection):lhs, lhs_params = self.process_lhs(compiler, connection)rhs, rhs_params = self.process_rhs(compiler, connection)params = lhs_params + rhs_paramsreturn '%s <> %s' % (lhs, rhs), params

    它可以像往常一样使用:

    results = Model.objects.exclude(a=True, x__ne=5)

等待设计决策。同时,使用exclude()

Django问题跟踪器具有显着的条目#5763,标题"Queryset没有"不相等"的过滤器运算符"这是值得注意的,因为(截至2016年4月)它是“9年前开放”(在Django石器时代),“四年前关闭”,并且“最近一次更改是5个月前”。

通读讨论,很有趣。基本上,有些人认为应该添加__ne而其他人说exclude()更清晰,因此__ne应该添加没有

(我同意前者,因为后者的论点是大致相当于说Python不应该有!=,因为它已经有==not了…)

您要查找的是所有具有a=falsex=5的对象。在Django中,|在查询集之间充当OR运算符:

results = Model.objects.filter(a=false)|Model.objects.filter(x=5)

结果=Model.objects.filter(a=True).排除(x=5)
Generetes this sql:
从tablex中选择*其中a!=0和x!=5
sql取决于您的True/False字段的表示方式以及数据库引擎。不过,django代码就是您所需要的全部。

Django模型值(披露:作者)提供了不平等查找的实现,如这个答案所示。它还为它提供了语法支持:

from model_values import FModel.objects.exclude(F.x != 5, a=True)

使用排除和过滤

results = Model.objects.filter(x=5).exclude(a=true)

小心这个问题的许多错误答案!

Gerard的逻辑是正确的,尽管它将返回一个列表而不是一个查询集(这可能无关紧要)。

如果您需要查询集,请使用Q:

from django.db.models import Qresults = Model.objects.filter(Q(a=false) | Q(x=5))

这会给你想要的结果。

from django.db.models import Qresults = Model.objects.exclude(Q(a=True) & ~Q(x=5))

对于不等于,您可以在相等查询上使用~。显然,Q可用于到达相等查询。

如果我们需要根据我们可以使用的子查询集排除/否定,

条件过滤器

当条件表达式返回布尔值时,可以直接在过滤器中使用它。这里non_unique_account_type返回一个布尔值。但是,我们仍然可以在过滤器中使用它。

>>> non_unique_account_type = Client.objects.filter(...     account_type=OuterRef('account_type'),... ).exclude(pk=OuterRef('pk')).values('pk')>>> Client.objects.filter(~Exists(non_unique_account_type))

在SQL,它评估为:

SELECT * FROM client c0WHERE NOT EXISTS (SELECT c1.idFROM client c1WHERE c1.account_type = c0.account_type AND NOT c1.id = c0.id)

这应该能行

results = Model.objects.filter(x=5).exclude(a=True)