summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClifford Gama <cliffygamy@gmail.com>2025-10-25 18:41:08 +0200
committerJacob Walls <jacobtylerwalls@gmail.com>2025-12-22 14:20:07 -0500
commit6ee8e9d56c17eb0014e73189950a9e8de2a8ec0e (patch)
tree0947d7b96d288effe728b8db62fb2345f64313f7
parent9cc5c87ffb989991524ee4eb91a435d2296ded2b (diff)
Fixed #36508 -- Interpreted __iexact=None on KeyTransforms as __exact=None.
Thanks Jacob Walls for the report.
-rw-r--r--django/db/models/fields/json.py14
-rw-r--r--docs/releases/6.1.txt5
-rw-r--r--tests/model_fields/test_jsonfield.py6
3 files changed, 24 insertions, 1 deletions
diff --git a/django/db/models/fields/json.py b/django/db/models/fields/json.py
index 71c3f4d335..cf4f5953a7 100644
--- a/django/db/models/fields/json.py
+++ b/django/db/models/fields/json.py
@@ -665,7 +665,19 @@ class KeyTransformExact(JSONExact):
class KeyTransformIExact(
CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IExact
):
- pass
+ can_use_none_as_rhs = True
+
+ def as_sql(self, compiler, connection):
+ if self.rhs is None:
+ # Interpret __iexact=None on KeyTextTransform as __exact=None on
+ # KeyTransform.
+ keytransform = KeyTransform(self.lhs.key_name, self.lhs.lhs)
+ exact_lookup = keytransform.get_lookup("exact")(keytransform, self.rhs)
+ # Delegate to the backend vendor method, if it exists.
+ vendor = connection.vendor
+ as_vendor = getattr(exact_lookup, f"as_{vendor}", exact_lookup.as_sql)
+ return as_vendor(compiler, connection)
+ return super().as_sql(compiler, connection)
class KeyTransformIContains(
diff --git a/docs/releases/6.1.txt b/docs/releases/6.1.txt
index 2e6e7235d7..c4ecefc08a 100644
--- a/docs/releases/6.1.txt
+++ b/docs/releases/6.1.txt
@@ -400,6 +400,11 @@ Miscellaneous
* The minimum supported version of SQLite is increased from 3.31.0 to 3.37.0.
+* The :lookup:`iexact=None <iexact>` lookup on
+ :class:`~django.db.models.JSONField` key transforms now matches JSON
+ ``null``, to match the behavior of :lookup:`exact=None <exact>` on key
+ transforms. Previously, it was interpreted as an :lookup:`isnull` lookup.
+
.. _deprecated-features-6.1:
Features deprecated in 6.1
diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py
index 76cdc0e421..1afeef31eb 100644
--- a/tests/model_fields/test_jsonfield.py
+++ b/tests/model_fields/test_jsonfield.py
@@ -782,6 +782,12 @@ class TestQuerying(TestCase):
[self.objs[4]],
)
+ def test_key_iexact_none(self):
+ self.assertSequenceEqual(
+ NullableJSONModel.objects.filter(value__j__iexact=None),
+ [self.objs[4]],
+ )
+
def test_none_key_exclude(self):
obj = NullableJSONModel.objects.create(value={"j": 1})
if connection.vendor == "oracle":