mirror of
https://github.com/django/django.git
synced 2025-03-06 07:22:32 +00:00
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.
This commit is contained in:
parent
7c7bc6391a
commit
10bfa876be
@ -1068,23 +1068,24 @@ class Query:
|
|||||||
lhs = self.try_transform(lhs, name)
|
lhs = self.try_transform(lhs, name)
|
||||||
# First try get_lookup() so that the lookup takes precedence if the lhs
|
# First try get_lookup() so that the lookup takes precedence if the lhs
|
||||||
# supports both transform and lookup for the name.
|
# 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 not lookup_class:
|
||||||
if lhs.field.is_relation:
|
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
|
# A lookup wasn't found. Try to interpret the name as a transform
|
||||||
# and do an Exact lookup against it.
|
# and do an Exact lookup against it.
|
||||||
lhs = self.try_transform(lhs, lookups[-1])
|
lhs = self.try_transform(lhs, lookup_name)
|
||||||
lookup_class = lhs.get_lookup('exact')
|
lookup_name = 'exact'
|
||||||
|
lookup_class = lhs.get_lookup(lookup_name)
|
||||||
if not lookup_class:
|
if not lookup_class:
|
||||||
return
|
return
|
||||||
|
|
||||||
lookup = lookup_class(lhs, rhs)
|
lookup = lookup_class(lhs, rhs)
|
||||||
# Interpret '__exact=None' as the sql 'is 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.
|
||||||
if lookup.rhs is None:
|
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")
|
raise ValueError("Cannot use None as a query value")
|
||||||
return lhs.get_lookup('isnull')(lhs, True)
|
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.
|
# 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.
|
# A similar thing is done in is_nullable(), too.
|
||||||
if (connections[DEFAULT_DB_ALIAS].features.interprets_empty_strings_as_nulls and
|
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 lhs.get_lookup('isnull')(lhs, True)
|
||||||
|
|
||||||
return lookup
|
return lookup
|
||||||
|
@ -240,6 +240,23 @@ class LookupTests(TestCase):
|
|||||||
models.DateField._unregister_lookup(YearTransform)
|
models.DateField._unregister_lookup(YearTransform)
|
||||||
models.DateField._unregister_lookup(YearTransform, custom_transform_name)
|
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):
|
def test_basic_lookup(self):
|
||||||
a1 = Author.objects.create(name='a1', age=1)
|
a1 = Author.objects.create(name='a1', age=1)
|
||||||
a2 = Author.objects.create(name='a2', age=2)
|
a2 = Author.objects.create(name='a2', age=2)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user