在查询集中过滤空或NULL名称


463

我有first_namelast_namealias(可选),我需要寻找。因此,我需要一个查询来给我所有具有别名集的名称。

仅在我可以做的情况下:

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

那么,什么等同于以上内容?

Answers:


839

您可以这样做:

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均为true的行被排除在外,因此我们得到两个字段都不为真的所有行。生成的SQL代码看起来像这样:

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

另外,如果您的逻辑比这更复杂,则可以使用Django的Q对象

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

有关更多信息,请参阅此页面以及Django文档中的此页面

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


5
我认为您的编辑是错误的:链接过滤器不会自动创建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 2013年

1
@shezi:我的意思更多是作为类比-我的意思并不是要保证实际的SQL代码使用OR来融合条件。我将编辑答案以澄清问题。
Sasha Chedygov 2013年

1
请记住,有多种方法可以表示此逻辑-例如,NOT (A AND B)等效于NOT A OR NOT B。我认为这会让熟悉SQL但不熟悉ORM的新Django开发人员感到困惑。
Sasha Chedygov 2013年

3
我知道De Morgan的定律,而这正是我的观点:您的示例仅适用ANDOR因为您正在使用,因此利用了将第一个查询中的转换为an的优势exclude。在一般情况下,将链接视为THEN,可能更正确exclude(A) THEN exclude(B)。对不起上面的苛刻语言。您的答案确实不错,但我担心新开发者会过于笼统地接受您的答案。
shezi 2013年

2
@shezi:足够公平。我同意,这是更好地在Django条件,而不是在SQL方面想起来,我只是想在这方面呈现链接AND,并OR可能是有人从一个SQL后台来Django的有用。为了更深入地了解Django,我认为文档比我能做的更好。
Sasha Chedygov

48
Name.objects.filter(alias__gt='',alias__isnull=False)

2
我不确定,但我认为alias__isnull=False条件是多余的。如果确定该字段Null将被第一子句排除?
2015年

除了我之前的评论/问题,我认为这里的肯定逻辑比其他一些答案更容易遵循。
2015年

@Bobble将取决于数据库的实现–将订购委托给数据库
wpercy

alias__gt是唯一适用于JSON类型列的东西,我想从JSON中排除空字符串,如{'something:''}。因此,工作语法为:jsoncolumnname__something__gt=''
Bartgras

38

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

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

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

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

那应该给您您想要的设置。


5

从Django 1.8开始,

from django.db.models.functions import Length

Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)

5
这似乎是“您可以做的事”,而不是您应该做的事。它通过两个简单的检查大大提高了查询的复杂性。
奥利(Oli)

3

为避免使用时出现常见错误exclude,请记住:

不能多个条件添加到exclude()块中filter。要排除多个条件,必须使用多个exclude()

不正确

User.objects.filter(email='example@example.com')。exclude(profile__nick_name ='',profile__avt ='')

正确的

User.objects.filter(email='example@example.com')。exclude(profile__nick_name ='')。exclude(profile__avt ='')


0

您可以简单地做到这一点:

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

@damon-我在回答的是等号,.filter(alias!="")但不是标题。我已经编辑了答案。但是,字符字段不应允许使用NULL值,而应将空字符串用于非值(按照惯例)。
Tim Tisdall

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.