mirror of
https://github.com/django/django.git
synced 2025-07-06 10:49:17 +00:00
queryset-refactor: Interpret qs.filter(foo=None) to be the same as qs.filter(foo__isnull=True). Refs #2737.
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6760 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
648a3d87a3
commit
a2418176fd
@ -679,13 +679,13 @@ class Query(object):
|
|||||||
else:
|
else:
|
||||||
lookup_type = parts.pop()
|
lookup_type = parts.pop()
|
||||||
|
|
||||||
# Interpret '__exact=None' as the sql '= NULL'; otherwise, reject all
|
# Interpret '__exact=None' as the sql 'is NULL'; otherwise, reject all
|
||||||
# uses of None as a query value.
|
# uses of None as a query value.
|
||||||
# FIXME: Weren't we going to change this so that '__exact=None' was the
|
if value is None:
|
||||||
# same as '__isnull=True'? Need to check the conclusion of the mailing
|
if lookup_type != 'exact':
|
||||||
# list thread.
|
raise ValueError("Cannot use None as a query value")
|
||||||
if value is None and lookup_type != 'exact':
|
lookup_type = 'isnull'
|
||||||
raise ValueError("Cannot use None as a query value")
|
value = True
|
||||||
elif callable(value):
|
elif callable(value):
|
||||||
value = value()
|
value = value()
|
||||||
|
|
||||||
@ -708,7 +708,8 @@ class Query(object):
|
|||||||
alias = join[LHS_ALIAS]
|
alias = join[LHS_ALIAS]
|
||||||
col = join[LHS_JOIN_COL]
|
col = join[LHS_JOIN_COL]
|
||||||
|
|
||||||
if (lookup_type == 'isnull' and value is True):
|
if lookup_type == 'isnull' and value is True and (len(join_list) > 1 or
|
||||||
|
len(join_list[0]) > 1):
|
||||||
# If the comparison is against NULL, we need to use a left outer
|
# If the comparison is against NULL, we need to use a left outer
|
||||||
# join when connecting to the previous model. We make that
|
# join when connecting to the previous model. We make that
|
||||||
# adjustment here. We don't do this unless needed because it's less
|
# adjustment here. We don't do this unless needed because it's less
|
||||||
|
@ -1137,7 +1137,12 @@ Examples::
|
|||||||
SQL equivalents::
|
SQL equivalents::
|
||||||
|
|
||||||
SELECT ... WHERE id = 14;
|
SELECT ... WHERE id = 14;
|
||||||
SELECT ... WHERE id = NULL;
|
SELECT ... WHERE id IS NULL;
|
||||||
|
|
||||||
|
**New in Django development version:** The semantics of ``id__exact=None`` have
|
||||||
|
changed in the development version. Previously, it was (intentionally)
|
||||||
|
converted to ``WHERE id = NULL`` at the SQL level, which would never match
|
||||||
|
anything. It has now been changed to behave the same as ``id__isnull=True``.
|
||||||
|
|
||||||
iexact
|
iexact
|
||||||
~~~~~~
|
~~~~~~
|
||||||
@ -1367,14 +1372,6 @@ SQL equivalent::
|
|||||||
|
|
||||||
SELECT ... WHERE pub_date IS NULL;
|
SELECT ... WHERE pub_date IS NULL;
|
||||||
|
|
||||||
.. admonition:: ``__isnull=True`` vs ``__exact=None``
|
|
||||||
|
|
||||||
There is an important difference between ``__isnull=True`` and
|
|
||||||
``__exact=None``. ``__exact=None`` will *always* return an empty result
|
|
||||||
set, because SQL requires that no value is equal to ``NULL``.
|
|
||||||
``__isnull`` determines if the field is currently holding the value
|
|
||||||
of ``NULL`` without performing a comparison.
|
|
||||||
|
|
||||||
search
|
search
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
|
@ -80,6 +80,11 @@ None
|
|||||||
>>> Article.objects.filter(reporter__isnull=True)
|
>>> Article.objects.filter(reporter__isnull=True)
|
||||||
[<Article: Third>]
|
[<Article: Third>]
|
||||||
|
|
||||||
|
# We can achieve the same thing by filtering for the case where the reporter is
|
||||||
|
# None.
|
||||||
|
>>> Article.objects.filter(reporter=None)
|
||||||
|
[<Article: Third>]
|
||||||
|
|
||||||
# Set the reporter for the Third article
|
# Set the reporter for the Third article
|
||||||
>>> r.article_set.add(a3)
|
>>> r.article_set.add(a3)
|
||||||
>>> r.article_set.all()
|
>>> r.article_set.all()
|
||||||
|
@ -24,10 +24,15 @@ __test__ = {'API_TESTS':"""
|
|||||||
>>> c2 = Choice(poll=p1, choice='Why Not?')
|
>>> c2 = Choice(poll=p1, choice='Why Not?')
|
||||||
>>> c2.save()
|
>>> c2.save()
|
||||||
|
|
||||||
# Exact query with value None returns nothing (=NULL in sql)
|
# Exact query with value None returns nothing ("is NULL" in sql, but every 'id'
|
||||||
|
# field has a value).
|
||||||
>>> Choice.objects.filter(id__exact=None)
|
>>> Choice.objects.filter(id__exact=None)
|
||||||
[]
|
[]
|
||||||
|
|
||||||
|
Excluding the previous result returns everything.
|
||||||
|
>>> Choice.objects.exclude(id=None).order_by('id')
|
||||||
|
[<Choice: Choice: Because. in poll Q: Why? >, <Choice: Choice: Why Not? in poll Q: Why? >]
|
||||||
|
|
||||||
# Valid query, but fails because foo isn't a keyword
|
# Valid query, but fails because foo isn't a keyword
|
||||||
>>> Choice.objects.filter(foo__exact=None)
|
>>> Choice.objects.filter(foo__exact=None)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user