关于python:如何在Django查询集过滤中做不相等的操作?

How do I do a not equal in Django queryset filtering?

在django模型查询集中,我看到比较值有__gt__lt,但是有__ne!=<>吗(不等于?)

我想用一个不等于:

例子:

1
2
3
Model:
    bool a;
    int x;

我想要

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

!=语法不正确。我试过__ne<>

我最终使用了:

1
results = Model.objects.exclude(a=true, x__lt=5).exclude(a=true, x__gt=5)

  • 结果=model.objects.exclude(a=true).filter(x=5)是否有效?
  • @休布朗。不,您的查询首先排除所有a=true,然后对其余的应用x=5过滤器。预期查询只需要使用a=truex!=5的查询。不同的是,所有带有a=truex=5的都被过滤掉了。


也许Q对象可以帮助解决这个问题。我从来没有使用过它们,但它们似乎可以被否定并组合起来,就像普通的Python表达式一样。

最新消息:我刚试过,看起来效果不错:

1
2
3
4
5
6
>>> 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>, ...]

  • @j.c.leit&227;o:有关更直观的语法,请参见下面的@d4nt答案。


您的查询似乎有一个双负数,您希望排除X不是5的所有行,所以换句话说,您希望包括X是5的所有行。我相信这会成功的。

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

要回答您的特定问题,没有"不等于"的方法,但这可能是因为Django有"filter"和"exclude"两种可用方法,因此您可以随时切换逻辑轮以获得所需的结果。

  • @我可能是错的,但我认为应该是results = Model.objects.filter(a=true).exclude(x=5)
  • @塔兰杰特:我想你误解了最初的问题。d4nt的版本是正确的,因为op想要排除(a=true)和否定x=5的排除(即包括它)。
  • 我认为这是错误的,因为错误地排除了一个实例(x=4,a=false)。
  • 也就是说,顺序关系到objects.exclude(**filter1).filter(**filter2)objects.filter(**filter1).exclude(**filter2)的结果不同,~q在objects.filter(**filter_with_Q)内部总是得到正确的否定。
  • @达尼戈萨,这似乎不对。我自己也试过,但是excludefilter的通话顺序没有任何意义。WHERE条款中的条件顺序发生了变化,但这又有什么关系呢?
  • @丹尼戈萨排除和过滤顺序并不重要。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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对象结合起来,并使用Jason Baker建议的filter()exclude(),您就可以得到任何可能的查询所需要的东西。

  • 谢谢,这太棒了。我用过像这样的东西,它很管用。
  • @Suhail,请注意,并非所有数据库都支持regex语法:)
  • 我在icontains中,iexact和类似的词代表"忽略大小写敏感性"。它不是"逆"的。
  • 值得注意的是,当您使用多个术语的exclude()时,您可能希望与OR操作符(例如exclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2))操作符)组合该命题,以便排除这两种条件下的结果。


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

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

1
2
3
4
5
6
7
8
9
10
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

然后您需要注册它:

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

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

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

  • 回答得很好,而且实际上是唯一一个真正回答这个问题的人。
  • 天哪,这真的有效,甚至在管理员的网址。很好的回答,谢谢。


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

  • excludefilter

    1
    results = Model.objects.exclude(a=true).filter(x=5)
  • 使用Q()对象和~操作符

    1
    2
    from django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
  • 注册自定义查找函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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

    django 1.8增加了register_lookup装饰像往常一样启用自定义查找:

    1
    results = Model.objects.exclude(a=True, x__ne=5)
    • object_list=queryset.filter(~q(a=true),x=5):记住将不包含q的所有其他条件保留在包含q的条件之后。
    • @布米辛哈尔为什么?
    • @michaelhofmann:a)排除后,您将使用~q过滤较小的数据集,这样更有效。b)可能相反的排序方式不起作用。不知道…别忘了!


    在使用模型时,可以使用=__gt__gte__lt__lte,不能使用ne!=<>。但是,您可以在使用q对象时实现更好的过滤。

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

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


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

    Django问题追踪系统有一个显著的条目5763,标题为"queryset没有"not equal"筛选器运算符"。这是值得注意的,因为(截至2016年4月)"9年前开业"(在姜戈石器时代)"4年前关闭",以及"最近5个月前改变了"。

    看完讨论,很有趣。基本上,有些人认为应该增加1(14)而另一些人则认为exclude()更清晰,因此__ne更清晰。不应添加。

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


    你应该这样使用filterexclude

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

    使用排除和筛选

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

    最后一位代码将排除X处的所有对象!=5,a为真。试试这个:

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

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

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


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

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


    django model values(disclosure:author)提供了notequal查找的实现,如此答案所示。它还为它提供语法支持:

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

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

    生成此SQL:

    1
    select * from tablex where a != 0 and x !=5

    SQL取决于表示真/假字段的方式和数据库引擎。不过,Django代码是您所需要的。


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

    杰拉德的逻辑是正确的,尽管它将返回一个列表而不是一个查询集(这可能不重要)。

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

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