【问题标题】:How to filter empty or NULL names in a QuerySet?如何过滤 QuerySet 中的空名称或 NULL 名称?
【发布时间】:2010-10-25 01:54:03
【问题描述】:

我有需要搜索的 first_namelast_namealias(可选)。所以,我需要一个查询来给我所有有别名集的名字。

只要我能做到:

Name.objects.filter(alias!="")

那么,上面的等价物是什么?

【问题讨论】:

    标签: django django-models django-queryset filter null


    【解决方案1】:

    你可以这样做:

    Name.objects.exclude(alias__isnull=True)
    

    如果您需要排除空值空字符串,这样做的首选方法是将条件链接在一起,如下所示:

    Name.objects.exclude(alias__isnull=True).exclude(alias__exact='')
    

    将这些方法链接在一起基本上独立检查每个条件:在上面的示例中,我们排除了 alias 为 null 为空字符串的行,因此您将获得所有 Name 具有非空、非空 alias 字段。生成的 SQL 如下所示:

    SELECT * FROM Name WHERE alias IS NOT NULL AND alias != ""
    

    您还可以将多个参数传递给对exclude 的单个调用,这将确保仅排除满足每个条件的对象:

    Name.objects.exclude(some_field=True, other_field=True)
    

    在这里,some_field other_field 为真的行被排除,因此我们得到所有两个字段都不为真的行。生成的 SQL 代码看起来有点像这样:

    SELECT * FROM Name WHERE NOT (some_field = TRUE AND other_field = TRUE)
    

    或者,如果您的逻辑比这更复杂,您可以使用 Django 的Q objects

    from django.db.models import Q
    Name.objects.exclude(Q(alias__isnull=True) | Q(alias__exact=''))
    

    有关详细信息,请参阅 Django 文档中的 this pagethis page

    顺便说一句:我的 SQL 示例只是一个类比——实际生成的 SQL 代码可能看起来不同。通过实际查看它们生成的 SQL,您将更深入地了解 Django 查询的工作原理。

    【讨论】:

    • 我认为您的编辑是错误的:链接过滤器不会自动创建 SQL OR(仅在这种情况下),它会生成 SQL AND。请参阅此页面以供参考:docs.djangoproject.com/en/dev/topics/db/queries/… 链接的优点是您可以混合使用excludefilter 来对复杂的查询条件进行建模。如果你想为真实的 SQL OR 建模,你必须使用 Django Q 对象:docs.djangoproject.com/en/dev/topics/db/queries/… 请编辑你的编辑以反映这一点,因为它的答案具有严重的误导性。
    • @shezi:我的意思更像是一个类比——我并不是说实际的 SQL 代码保证使用OR 来融合条件。我将编辑我的答案以澄清。
    • 请记住,有不同的方式来表示这个逻辑——例如,NOT (A AND B) 等价于NOT A OR NOT B。我认为这会让了解 SQL 但不熟悉 ORM 的新 Django 开发人员感到困惑。
    • 我知道德摩根定律,这正是我的观点:您的示例之所以有效,是因为它利用了将第一个查询中的 AND 转换为 OR 的优势,因为您使用的是 @ 987654348@。在一般情况下,将链接视为THEN 可能更正确,即exclude(A) THEN exclude(B)。对上面的苛刻语言感到抱歉。您的回答确实不错,但我担心新开发人员会过于笼统地接受您的回答。
    • @shezi:很公平。我同意最好用 Django 术语而不是 SQL 术语来考虑它,我只是认为以 ANDOR 的形式呈现链接可能对从 SQL 背景进入 Django 的人有用。为了更深入地了解 Django,我认为文档做得比我做得更好。
    【解决方案2】:

    首先,Django 文档强烈建议不要对基于字符串的字段(例如 CharField 或 TextField)使用 NULL 值。阅读说明文档:

    https://docs.djangoproject.com/en/dev/ref/models/fields/#null

    解决方案: 我认为,您还可以将 QuerySets 上的方法链接在一起。试试这个:

    Name.objects.exclude(alias__isnull=True).exclude(alias="")
    

    这应该会给你你正在寻找的集合。

    【讨论】:

      【解决方案3】:
      Name.objects.filter(alias__gt='',alias__isnull=False)
      

      【讨论】:

      • 我不确定,但我认为alias__isnull=False 条件是多余的。如果字段是Null,肯定会被第一个子句排除?
      • 除了我之前的评论/问题之外,我认为这里的积极逻辑比其他一些答案更容易理解。
      • @Bobble 取决于数据库实现 -- ordering is delegated to the databse
      • alias__gt 是唯一适用于我想从 JSON 中排除空字符串的 JSON 类型列,例如 {'something:''}。所以工作语法是:jsoncolumnname__something__gt=''
      【解决方案4】:

      从 Django 1.8,

      from django.db.models.functions import Length
      
      Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)
      

      【讨论】:

      • 这似乎是“你可以做的事”,而不是你应该做的事。它通过两个简单的检查显着增加了查询的复杂性。
      【解决方案5】:

      你可以这样做:

      Name.objects.exclude(alias="").exclude(alias=None)
      

      真的就是这么简单。 filter 用于匹配,exclude 用于匹配除指定内容之外的所有内容。这将在 SQL 中评估为NOT alias='' AND alias IS NOT NULL

      【讨论】:

      • 这是不正确的。该问题旨在从查询中排除空 (alias="") 和 NULL (alias=None) 别名。您的将包括带有Name(alias=None) 的实例。
      • @damon - 我正在回答与.filter(alias!="") 等效的内容,但不是标题。我已经编辑了我的答案。但是,字符字段不应允许 NULL 值,并且将空字符串用于非值(按照惯例)。
      【解决方案6】:

      这是另一种简单的方法。

      Name.objects.exclude(alias=None)
      

      【讨论】:

      • None"" 不同。
      【解决方案7】:

      1.使用排除时,请记住以下几点以避免常见错误:

      应该多个条件添加到an exclude() 块中,例如filter()。要排除多个条件,您应该使用 multiple exclude()

      示例:(NOT a AND NOT b)

      Entry.objects.exclude(title='').exclude(headline='')
      

      等于

      SELECT... WHERE NOT title = '' AND NOT headline = ''
      

      ================================================ =======

      2。仅在您真正了解时才使用多个:

      例如:NOT (a AND b)

      Entry.objects.exclude(title='', headline='')
      

      等于

      SELECT.. WHERE NOT (title = '' AND headline = '')
      

      【讨论】:

      • 您确定以上要声明的内容吗?
      • docs 非常清楚,您可以在 .exclude() 中包含多个条件,但它们的工作方式与单独的条件不同。和NOT (a AND b)(NOT a AND NOT b)的区别一样。
      • 谢谢;我已经进行了必要的更改。
      【解决方案8】:

      另一种使用通用isempty 查找的方法,可用于任何字段。

      它也可以被 django rest_framework 或其他使用 django 查找的应用程序使用:

      from distutils.util import strtobool
      from django.db.models import Field
      from django.db.models.lookups import BuiltinLookup
      
      @Field.register_lookup
      class IsEmpty(BuiltinLookup):
          lookup_name = 'isempty'
          prepare_rhs = False
      
          def as_sql(self, compiler, connection):
              sql, params = compiler.compile(self.lhs)
              condition = self.rhs if isinstance(self.rhs, bool) else bool(strtobool(self.rhs))
              if condition:
                  return "%s IS NULL or %s = ''" % (sql, sql), params
              else:
                  return "%s <> ''" % sql, params
      

      然后你可以像这样使用它:

      Name.objects.filter(alias__isempty=False)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-24
        • 2022-10-17
        • 2014-10-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-03
        • 1970-01-01
        相关资源
        最近更新 更多