ChatGPT解决这个技术问题 Extra ChatGPT

如何在 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)
results = Model.objects.exclude(a=true).filter(x=5) 会起作用吗?
@hughdbrown。否。您的查询首先排除所有 a=true,然后对其余的应用 x=5 过滤器。预期的查询仅需要具有 a=truex!=5 的查询。不同之处在于所有带有 a=truex=5 的人也被过滤掉了。

B
Boris Verkhovskiy

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

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

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

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

[<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 是不对的。
这是有道理的……如果您要在注释或聚合中进行过滤,这将派上用场。
一个典型的用途是知道是否存在具有不同参数的对象:Entry.objects.filter(~Q(param="good")).exists()
B
Boris Verkhovskiy

您的查询似乎有双重否定,您想要排除 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 的排除和过滤顺序无关紧要。
B
Boris Verkhovskiy

查询中的 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,请注意并非所有数据库都支持该正则表达式语法:)
icontainsiexact 和类似中的 i 代表“忽略区分大小写”。它不适用于“逆”。
值得注意的是,当您将 exclude() 与多个术语一起使用时,您可能希望使用 OR 运算符组成命题,例如 exclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2)),以便排除两种条件下的结果。
B
Boris Verkhovskiy

有三个选项:

链式排除和过滤结果 = Model.objects.exclude(a=True).filter(x=5) 使用 Q() 对象和 ~ 操作符 from django.db.models import Q object_list = QuerySet.filter(~Q(a =True), x=5) 从 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 , 连接): 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。 @阿努帕姆
B
Boris Verkhovskiy

创建自定义查找很容易,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)

B
Boris Verkhovskiy

虽然您可以使用 =__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')

L
Lutz Prechelt

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

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

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

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


这不是一个未决的设计决定,他们在 8 年前决定不这样做。
P
Philip John

使用排除和过滤

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

这与 @d4nt's answer 比你早 8 年离开和 @outoftime's answer 比这个早 3 年有什么不同?
o
outoftime

您应该像这样使用 filterexclude

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

这与您 5 年前制作的 @d4nt's answer 有何不同?
A
A. Coady

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

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

t
tzot

这将给出您想要的结果。

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-operationsdocs.python.org/3/reference/…
J
Jason Baker

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

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

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


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

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

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

M
M. Dasn

results = Model.objects.filter(a = True).exclude(x = 5)
select * from tablex where a != 0 and x !=5


Y
Yusuf Ganiyu

这应该工作

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

M
Mark Bailey

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

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

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

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

“Gerard 的 [...] 将返回一个列表而不是一个查询集”——这不是真的。它返回一个查询集。您的答案与接受的答案相同。
S
Siva Sankar

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

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
)