如何在 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=true
和x!=5
的查询。不同之处在于所有带有a=true
和x=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 同时提供了filter
和exclude
方法,因此您可以随时切换逻辑以获得所需的结果.
【讨论】:
@d4nt:我可能错了,但我认为查询应该是results = Model.objects.filter(a=true).exclude(x=5)
@Taranjeet:我认为您误读了原始查询。 d4nt 的版本是正确的,因为 OP 想要排除(a=True)并否定排除 x=5(即包含它)。
我认为这是错误的,因为实例 (x=4, a=false) 会被错误地排除。
@danigosa 这似乎不对。我自己也试过了,exclude
和 filter
调用的顺序并没有产生任何有意义的区别。 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】:你应该像这样使用filter
和exclude
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 !=5sql 取决于您的 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 查询集过滤中执行不等于?的主要内容,如果未能解决你的问题,请参考以下文章