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

Posted

技术标签:

【中文标题】如何在 Django 查询集过滤中执行不等于?【英文标题】:How do I do a not equal in Django queryset filtering? 【发布时间】:2010-10-15 19:06:52 【问题描述】:

在 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)

【问题讨论】:

结果 = Model.objects.exclude(a=true).filter(x=5) 会起作用吗? @hughdbrown。否。您的查询首先排除所有a=true,然后对其余的应用x=5 过滤器。预期的查询仅需要具有a=truex!=5 的查询。不同之处在于所有带有a=truex=5 的人也会被过滤掉。 【参考方案1】:

您可以为此使用Q objects。它们可以用 ~ 运算符取反,并可以像普通的 Python 表达式一样组合:

from myapp.models import Entry
from django.db.models import Q

Entry.objects.filter(~Q(id=3))

将返回除 ID 为 3 的所有条目:

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

【讨论】:

有什么理由做Entry.objects.filter(~Q(id=3))而不是Entry.objects.exclude(id=3) 我想它的使用取决于场景,但 Q 对象允许更复杂的查询。例如,您也可以将~Q 查询与其他查询串在一起。 docs.djangoproject.com/en/3.2/topics/db/queries/… @BobWhitelock:这只是一个简单的问题。在现实世界中,很多情况下我们必须使用它。例如:EXCLUDE(A=1 and B__not=2);使用额外的 .exclude 是不对的。 这很有道理...如果您要在注释或聚合中进行过滤,这会派上用场。【参考方案2】:

您的查询似乎有一个双重否定,您想要排除 x 不是 5 的所有行,换句话说,您想要包括 x 5 的所有行。我相信这会成功:

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

要回答您的具体问题,没有“不等于”field lookup,但这可能是因为 Django 同时提供了filterexclude 方法,因此您可以随时切换逻辑以获得所需的结果.

【讨论】:

@d4nt:我可能错了,但我认为查询应该是results = Model.objects.filter(a=true).exclude(x=5) @Taranjeet:我认为您误读了原始查询。 d4nt 的版本是正确的,因为 OP 想要排除(a=True)并否定排除 x=5(即包含它)。 我认为这是错误的,因为实例 (x=4, a=false) 会被错误地排除。 @danigosa 这似乎不对。我自己也试过了,excludefilter 调用的顺序并没有产生任何有意义的区别。 WHERE 子句中的条件顺序发生了变化,但这有什么关系呢? @danigosa 排除和过滤的顺序无关紧要。【参考方案3】:

查询中的field=value 语法是field__exact=value 的简写。也就是说Django puts query operators on query fields in the identifiers。 Django 支持以下运算符:

exact
iexact
contains
icontains
in
gt
gte
lt
lte
startswith
istartswith
endswith
iendswith
range

date
year
iso_year
month
day
week
week_day
iso_week_day
quarter
time
hour
minute
second

isnull
regex
iregex

我确信通过将这些与 Q 对象组合为Dave Vogt suggests 并使用filter()exclude() 作为Jason Baker suggests,您将获得几乎所有可能查询所需的内容。

【讨论】:

感谢这太棒了。我使用了类似tg=Tag.objects.filter(user=request.user).exclude(name__regex=r'^(public|url)$') 的东西,它可以工作。 @suhail,请注意并非所有数据库都支持该正则表达式语法:) i in icontains, iexact 和类似的代表“忽略大小写敏感”。它不适用于“逆”。 值得注意的是,当您使用带有多个术语的exclude() 时,您可能希望使用OR 运算符来组合命题,例如exclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2)) 以排除两种情况下的结果。【参考方案4】:

共有三个选项:

    Chain exclude and filter

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

    使用Q() objects 和~ operator

    from django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
    

    注册custom lookup function

    from django.db.models import Lookup
    from django.db.models import Field
    
    @Field.register_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_params
            return '%s <> %s' % (lhs, rhs), params
    

    哪些可以照常使用:

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

【讨论】:

object_list = QuerySet.filter(~Q(a=True), x=5) : 请记住将所有其他不包含 Q 的条件保留在包含 Q 的条件之后。 @MichaelHoffmann :A)然后,您将在使用 ~Q 排除后过滤一组较小的数据,这样效率更高。 B)可能反过来排序不起作用..不知道..不记得! 想知道1 vs 2是否有性能差异 注意:exclude 将在 WHERE 子句中添加一些内容,因此它非常有效。见docs.djangoproject.com/en/3.2/ref/models/querysets/#exclude。 @Anupam【参考方案5】:

创建自定义查找很容易,Django's official documentation 中有一个__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_params
        return '%s <> %s' % (lhs, rhs), params

那你需要注册一下:

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

现在您可以像这样在查询中使用__ne 查找:

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

【讨论】:

【参考方案6】:

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

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

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

【讨论】:

【参考方案7】:

待定的设计决定。同时,使用exclude()

Django 问题跟踪器具有非凡的entry #5763, 标题为“查询集没有“不等于”过滤运算符”。 这很了不起,因为(截至 2016 年 4 月) “9 年前开业”(在 Django 石器时代), “4 年前关闭”,以及 “最近一次更改是 5 个月前”。

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

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

【讨论】:

这不是一个未决的设计决定,他们在 8 年前就决定不这样做了。【参考方案8】:

使用排除和过滤

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

【讨论】:

这和@d4nt's answer比你早8年和@outoftime's answer比这个早3年有什么不同?【参考方案9】:

你应该像这样使用filterexclude

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

【讨论】:

这和你之前 5 年制作的 @d4nt's answer 有什么不同?【参考方案10】:

Django-model-values(披露:作者)提供了NotEqual 查找的实现,如this answer。它还为其提供语法支持:

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

【讨论】:

【参考方案11】:

这将给出您想要的结果。

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

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

【讨论】:

请检查编辑;在Q(a=True) and ~Q(x=5) 中使用“and”将评估为~Q(x=5) 作为.exclude 的参数。请阅读:docs.python.org/3/reference/expressions.html#boolean-operations 和 docs.python.org/3/reference/…。【参考方案12】:

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

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

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

【讨论】:

这不是 100% 相同的事情,因为这些字段也可能有 Null 值。 这仅返回具有 a=False and x=5 的那些项目,但在问题中将包含一个实例 (a=false, x=4)。 results = Model.objects.filter(a__in=[False,None],x=5)【参考方案13】:

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

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

【讨论】:

【参考方案14】:

results = Model.objects.filter(a = True).exclude(x = 5)
生成这个 sql:
select * from tablex where a != 0 and x !=5
sql 取决于您的 True/False 字段的表示方式以及数据库引擎。 django 代码就是你所需要的。

【讨论】:

【参考方案15】:

注意这个问题的许多错误答案!

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

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

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

【讨论】:

“Gerard 的 [...] 将返回一个列表而不是一个查询集”——这不是真的。它返回一个查询集。而且你的答案和接受的答案是一样的。【参考方案16】:

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

Conditional filter:

当条件表达式返回一个布尔值时,可以直接在过滤器中使用它。这里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 c0
WHERE NOT EXISTS (
  SELECT c1.id
  FROM client c1
  WHERE c1.account_type = c0.account_type AND NOT c1.id = c0.id
)

【讨论】:

以上是关于如何在 Django 查询集过滤中执行不等于?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django 中过滤查询集的多对多

Django如何过滤多对多字段中的对象,而不是原始查询集

如何在 django admin 的 changelist_view 中过滤查询集?

如何使用 Django 中另一个查询集的结果过滤查询集?

如何使用动态过滤器制作 django 查询集?

如何在Django Admin中过滤foreignkey字段的查询集