[3.1.x] Fixed #32252 -- Fixed __isnull=True on key transforms on SQLite and Oracle.

__isnull=True on key transforms should not match keys with NULL values.

Backport of 8d7085e0fd from master
This commit is contained in:
sage 2020-12-09 21:45:18 +07:00 committed by Mariusz Felisiak
parent ce7f8c2ead
commit a891e1bb0a
3 changed files with 22 additions and 5 deletions

View File

@ -368,14 +368,25 @@ class CaseInsensitiveMixin:
class KeyTransformIsNull(lookups.IsNull): class KeyTransformIsNull(lookups.IsNull):
# key__isnull=False is the same as has_key='key' # key__isnull=False is the same as has_key='key'
def as_oracle(self, compiler, connection): def as_oracle(self, compiler, connection):
sql, params = HasKey(
self.lhs.lhs,
self.lhs.key_name,
).as_oracle(compiler, connection)
if not self.rhs: if not self.rhs:
return HasKey(self.lhs.lhs, self.lhs.key_name).as_oracle(compiler, connection) return sql, params
return super().as_sql(compiler, connection) # Column doesn't have a key or IS NULL.
lhs, lhs_params, _ = self.lhs.preprocess_lhs(compiler, connection)
return '(NOT %s OR %s IS NULL)' % (sql, lhs), tuple(params) + tuple(lhs_params)
def as_sqlite(self, compiler, connection): def as_sqlite(self, compiler, connection):
template = 'JSON_TYPE(%s, %%s) IS NULL'
if not self.rhs: if not self.rhs:
return HasKey(self.lhs.lhs, self.lhs.key_name).as_sqlite(compiler, connection) template = 'JSON_TYPE(%s, %%s) IS NOT NULL'
return super().as_sql(compiler, connection) return HasKey(self.lhs.lhs, self.lhs.key_name).as_sql(
compiler,
connection,
template=template,
)
class KeyTransformIn(lookups.In): class KeyTransformIn(lookups.In):

View File

@ -9,4 +9,6 @@ Django 3.1.5 fixes several bugs in 3.1.4.
Bugfixes Bugfixes
======== ========
* ... * Fixed ``__isnull=True`` lookup on key transforms for
:class:`~django.db.models.JSONField` with Oracle and SQLite
(:ticket:`32252`).

View File

@ -534,6 +534,10 @@ class TestQuerying(TestCase):
NullableJSONModel.objects.filter(value__a__isnull=True), NullableJSONModel.objects.filter(value__a__isnull=True),
self.objs[:3] + self.objs[5:], self.objs[:3] + self.objs[5:],
) )
self.assertSequenceEqual(
NullableJSONModel.objects.filter(value__j__isnull=True),
self.objs[:4] + self.objs[5:],
)
self.assertSequenceEqual( self.assertSequenceEqual(
NullableJSONModel.objects.filter(value__a__isnull=False), NullableJSONModel.objects.filter(value__a__isnull=False),
[self.objs[3], self.objs[4]], [self.objs[3], self.objs[4]],