如何在Django queryset过滤中执行不等于?


664

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

75
结果= Model.objects.exclude(a = true).filter(x = 5)是否有效?
hughdbrown

3
@hughdbrown。否。您的查询会a=true首先排除所有内容,然后x=5对其余内容应用过滤器。预期查询仅需要使用a=true和的查询x!=5。区别在于所有带有a=true和的x=5对象也被过滤掉了。
米切尔范祖伊伦

Answers:


689

也许Q对象可以解决这个问题。我从未使用过它们,但似乎可以将它们取反并组合起来,就像普通的python表达式一样。

更新:我只是尝试了一下,它似乎工作得很好:

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

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

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

16
@JCLeitão:有关更直观的语法,另请参见以下@ d4nt的答案
Paul D. Waite 2014年

610

您的查询似乎有一个双重否定,您想排除x不为5的所有行,换句话说,您想包括x为5的所有行。我相信这可以解决问题。

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

要回答您的特定问题,不存在“不等于”的问题,但这可能是因为django同时提供了“过滤器”和“排除”方法,因此您始终可以切换逻辑回合以获得所需的结果。


2
@ d4nt:我可能是错的,但我认为查询应该是results = Model.objects.filter(a=true).exclude(x=5)
Taranjeet 2015年

1
@Taranjeet:我认为您误读了原始查询。d4nt的版本是正确的,因为OP希望排除(a = True)并排除x = 5的排除(即包括它)。
Chuck

3
我认为这是错误的,因为实例(x = 4,a = false)将被错误排除。
RemcoGerlich 2015年

4
@danigosa似乎不正确。我只是自己尝试了一下,并且excludefilter调用的顺序没有任何有意义的变化。WHERE子句中条件的顺序会发生变化,但这有什么关系呢?
coredumperror

4
@danigosa的排除和过滤顺序无关紧要。
EralpB

132

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

exact
iexact
contains
icontains
in
gt
gte
lt
lte
startswith
istartswith
endswith
iendswith
range
year
month
day
week_day
isnull
search
regex
iregex

我敢肯定,如Dave Vogt所建议的那样,将它们与Q对象结合使用,filter()或者exclude()Jason Baker所建议的那样使用,您将获得几乎所有可能查询所需的确切信息。


谢谢,这太棒了。我用这样的东西tg=Tag.objects.filter(user=request.user).exclude(name__regex=r'^(public|url)$'),它的工作原理。
suhailvs 2013年

@suhail,请注意,并非所有数据库都支持该正则表达式语法:)
Anoyz

2
我在中icontainsiexact类似代表“忽略大小写”。它不是用于“逆”。
常春藤成长

值得注意的是,当您使用exclude()多个术语时,您可能希望与OR运算符组合该命题,例如exclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2))为了排除两种情况下的结果。
clapas

98

使用Django 1.7创建自定义查找很容易。Django官方文档中有一个__ne查找示例。

您需要先创建查找本身:

from django.db.models import Lookup

class NotEqual(Lookup):
    lookup_name = 'ne'

    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = lhs_params + rhs_params
        return '%s <> %s' % (lhs, rhs), params

然后,您需要注册:

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

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

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

88

Django 1.9 / 1.10中,有三个选项。

  1. excludefilter

    results = Model.objects.exclude(a=true).filter(x=5)
  2. 使用Q()对象~运算符

    from django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
  3. 注册自定义查找功能

    from django.db.models import Lookup
    from django.db.models.fields 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

    register_lookup在加装饰的Django 1.8和启用自定义查找和往常一样:

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

1
object_list中= QuerySet.filter(〜Q(一个= TRUE)中,x = 5):记住保持所有那些含有Q.后不含有Q中的其它条件
Bhumi辛格

1
@MichaelHoffmann:A)在使用〜Q排除之后,您将对较小的数据集进行过滤,因此效率更高。B)可能相反的排序方法不起作用.. dun知道.. dun记住!
普密蓬·辛格

41

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

您可以避免链接QuerySet.filter()QuerySet.exlude(),并使用以下代码:

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

24

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

Django问题追踪器具有引人注目的条目#5763,标题为“ Queryset没有“不相等”的过滤运算符”。值得注意的是,(截至2016年4月)它是​​“在9年前开放”(在Django石器时代),“在4年前关闭”和“在5个月前最后一次更改”。

通读讨论,这很有趣。基本上,一些人认为__ne应增加也有人说exclude()是清晰的,因此__ne 应该添加。

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



18

您应该使用filterexclude喜欢这个

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

8

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

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

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


3
那不是100%相同的事情,因为这些字段也可能有Null值。
MikeN

这仅返回那些具有a = False x = 5的项,但是在问题中将包括一个实例(a = false,x = 4)。
RemcoGerlich 2015年

1
results = Model.objects.filter(a__in=[False,None],x=5)
杰里米

8

结果= Model.objects.filter(a = True).exclude(x = 5)
生成此sql:
从tablex中选择*,其中a = 0且x!= 5
sql取决于您的True / False字段的表示方式以及数据库引擎。Django代码是您所需要的。



6

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

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

5

这将给您想要的结果。

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

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


请检查编辑;使用“ and” in Q(a=True) and ~Q(x=5)将评估为~Q(x=5)作为的参数.exclude。请阅读:docs.python.org/3/reference/expressions.html#boolean-operationsdocs.python.org/3/reference/…
tzot

2

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

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

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

from django.db.models import Q
results = Model.objects.filter(Q(a=false) | Q(x=5))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.