From a891e1bb0a3e1b29a461784cd0bf717513e72f19 Mon Sep 17 00:00:00 2001 From: sage Date: Wed, 9 Dec 2020 21:45:18 +0700 Subject: [PATCH] [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 8d7085e0fd004af5431389f3d903aba6220d7957 from master --- django/db/models/fields/json.py | 19 +++++++++++++++---- docs/releases/3.1.5.txt | 4 +++- tests/model_fields/test_jsonfield.py | 4 ++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/django/db/models/fields/json.py b/django/db/models/fields/json.py index 5b9fe4b63a7..7a3b2d3578c 100644 --- a/django/db/models/fields/json.py +++ b/django/db/models/fields/json.py @@ -368,14 +368,25 @@ class CaseInsensitiveMixin: class KeyTransformIsNull(lookups.IsNull): # key__isnull=False is the same as has_key='key' def as_oracle(self, compiler, connection): + sql, params = HasKey( + self.lhs.lhs, + self.lhs.key_name, + ).as_oracle(compiler, connection) if not self.rhs: - return HasKey(self.lhs.lhs, self.lhs.key_name).as_oracle(compiler, connection) - return super().as_sql(compiler, connection) + return sql, params + # 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): + template = 'JSON_TYPE(%s, %%s) IS NULL' if not self.rhs: - return HasKey(self.lhs.lhs, self.lhs.key_name).as_sqlite(compiler, connection) - return super().as_sql(compiler, connection) + template = 'JSON_TYPE(%s, %%s) IS NOT NULL' + return HasKey(self.lhs.lhs, self.lhs.key_name).as_sql( + compiler, + connection, + template=template, + ) class KeyTransformIn(lookups.In): diff --git a/docs/releases/3.1.5.txt b/docs/releases/3.1.5.txt index 4a7fcc58764..0d111184461 100644 --- a/docs/releases/3.1.5.txt +++ b/docs/releases/3.1.5.txt @@ -9,4 +9,6 @@ Django 3.1.5 fixes several bugs in 3.1.4. Bugfixes ======== -* ... +* Fixed ``__isnull=True`` lookup on key transforms for + :class:`~django.db.models.JSONField` with Oracle and SQLite + (:ticket:`32252`). diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py index f041c659d17..a4bc9e24548 100644 --- a/tests/model_fields/test_jsonfield.py +++ b/tests/model_fields/test_jsonfield.py @@ -534,6 +534,10 @@ class TestQuerying(TestCase): NullableJSONModel.objects.filter(value__a__isnull=True), self.objs[:3] + self.objs[5:], ) + self.assertSequenceEqual( + NullableJSONModel.objects.filter(value__j__isnull=True), + self.objs[:4] + self.objs[5:], + ) self.assertSequenceEqual( NullableJSONModel.objects.filter(value__a__isnull=False), [self.objs[3], self.objs[4]],