summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Fedoseev <fedoseev.sergey@gmail.com>2017-12-06 15:58:02 +0500
committerTim Graham <timograham@gmail.com>2017-12-12 17:11:58 -1000
commit10bfa876be59feec24bb6a40fa11bece808ee405 (patch)
tree54842b45827be14a0921815588328f46b313a501
parent7c7bc6391a3e83566f9ace59955e63503bc76cee (diff)
Refs #27985 -- Reallowed using __exact=None as an alias for __isnull=True if a custom lookup class with lookup_name != None is registered as the exact lookup.
Regression in 58da81a5a372a69f0bac801c412b57f3cce5f188 and prerequisite for refs #28896.
-rw-r--r--django/db/models/sql/query.py19
-rw-r--r--tests/custom_lookups/tests.py17
2 files changed, 27 insertions, 9 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 81fcd6921f..7c88144fd2 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -1068,23 +1068,24 @@ class Query:
lhs = self.try_transform(lhs, name)
# First try get_lookup() so that the lookup takes precedence if the lhs
# supports both transform and lookup for the name.
- lookup_class = lhs.get_lookup(lookups[-1])
+ lookup_name = lookups[-1]
+ lookup_class = lhs.get_lookup(lookup_name)
if not lookup_class:
if lhs.field.is_relation:
- raise FieldError('Related Field got invalid lookup: {}'.format(lookups[-1]))
+ raise FieldError('Related Field got invalid lookup: {}'.format(lookup_name))
# A lookup wasn't found. Try to interpret the name as a transform
# and do an Exact lookup against it.
- lhs = self.try_transform(lhs, lookups[-1])
- lookup_class = lhs.get_lookup('exact')
-
- if not lookup_class:
- return
+ lhs = self.try_transform(lhs, lookup_name)
+ lookup_name = 'exact'
+ lookup_class = lhs.get_lookup(lookup_name)
+ if not lookup_class:
+ return
lookup = lookup_class(lhs, rhs)
# Interpret '__exact=None' as the sql 'is NULL'; otherwise, reject all
# uses of None as a query value.
if lookup.rhs is None:
- if lookup.lookup_name not in ('exact', 'iexact'):
+ if lookup_name not in ('exact', 'iexact'):
raise ValueError("Cannot use None as a query value")
return lhs.get_lookup('isnull')(lhs, True)
@@ -1093,7 +1094,7 @@ class Query:
# DEFAULT_DB_ALIAS isn't nice but it's the best that can be done here.
# A similar thing is done in is_nullable(), too.
if (connections[DEFAULT_DB_ALIAS].features.interprets_empty_strings_as_nulls and
- lookup.lookup_name == 'exact' and lookup.rhs == ''):
+ lookup_name == 'exact' and lookup.rhs == ''):
return lhs.get_lookup('isnull')(lhs, True)
return lookup
diff --git a/tests/custom_lookups/tests.py b/tests/custom_lookups/tests.py
index bdb27a224a..9661aebc49 100644
--- a/tests/custom_lookups/tests.py
+++ b/tests/custom_lookups/tests.py
@@ -240,6 +240,23 @@ class LookupTests(TestCase):
models.DateField._unregister_lookup(YearTransform)
models.DateField._unregister_lookup(YearTransform, custom_transform_name)
+ def test_custom_exact_lookup_none_rhs(self):
+ """
+ __exact=None is transformed to __isnull=True if a custom lookup class
+ with lookup_name != 'exact' is registered as the `exact` lookup.
+ """
+ class CustomExactLookup(models.Lookup):
+ lookup_name = 'somecustomlookup'
+
+ field = Author._meta.get_field('birthdate')
+ OldExactLookup = field.get_lookup('exact')
+ author = Author.objects.create(name='author', birthdate=None)
+ try:
+ type(field).register_lookup(Exactly, 'exact')
+ self.assertEqual(Author.objects.get(birthdate__exact=None), author)
+ finally:
+ type(field).register_lookup(OldExactLookup, 'exact')
+
def test_basic_lookup(self):
a1 = Author.objects.create(name='a1', age=1)
a2 = Author.objects.create(name='a2', age=2)