summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClifford Gama <cliffygamy@gmail.com>2025-06-12 09:35:07 +0200
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2025-06-16 10:41:24 +0200
commit1d89691c7481fbcef6a7bc396e41a651372c1cf3 (patch)
tree51220e906f893aba57cc15d455c46a351d8dbb0b
parent4de4edf2c05cc80c514c989db480f2fe23ad5ee2 (diff)
[5.2.x] Fixed #36453 -- Made When.condition resolve with for_save=False.
Value(None, JSONField()) when used in When.condition incorrectly resolved with for_save=True, resulting in the value being serialized as SQL NULL instead of JSON null. Regression in c1fa3fdd040718356e5a3b9a0fe699d73f47a940. Thanks to Thomas McKay for the report, and to David Sanders and Simon Charettes for the review. Co-authored-by: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Backport of 104cbfd44b9eff010daf0ef0e1ce434385855b13 from main.
-rw-r--r--django/db/models/expressions.py11
-rw-r--r--docs/releases/5.2.4.txt4
-rw-r--r--tests/expressions/tests.py17
3 files changed, 32 insertions, 0 deletions
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 49a29392da..b214be7fa5 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -1588,6 +1588,17 @@ class When(Expression):
def set_source_expressions(self, exprs):
self.condition, self.result = exprs
+ def resolve_expression(
+ self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False
+ ):
+ c = super().resolve_expression(query, allow_joins, reuse, summarize, for_save)
+ if for_save and c.condition is not None:
+ # Resolve condition with for_save=False, since it's used as a filter.
+ c.condition = self.condition.resolve_expression(
+ query, allow_joins, reuse, summarize, for_save=False
+ )
+ return c
+
def get_source_fields(self):
# We're only interested in the fields of the result expressions.
return [self.result._output_field_or_none]
diff --git a/docs/releases/5.2.4.txt b/docs/releases/5.2.4.txt
index ebfa556f23..521ed94d6c 100644
--- a/docs/releases/5.2.4.txt
+++ b/docs/releases/5.2.4.txt
@@ -12,3 +12,7 @@ Bugfixes
* Fixed a regression in Django 5.2.2 where :meth:`HttpRequest.get_preferred_type()
<django.http.HttpRequest.get_preferred_type>` incorrectly preferred more
specific media types with a lower quality (:ticket:`36447`).
+
+* Fixed a regression in Django 5.2.3 where ``Value(None, JSONField())`` used in
+ a :class:`~django.db.models.expressions.When` condition was incorrectly
+ serialized as SQL ``NULL`` instead of JSON ``null`` (:ticket:`36453`).
diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py
index 89601de85b..a06fbc6b95 100644
--- a/tests/expressions/tests.py
+++ b/tests/expressions/tests.py
@@ -29,6 +29,7 @@ from django.db.models import (
FloatField,
Func,
IntegerField,
+ JSONField,
Max,
Min,
Model,
@@ -81,6 +82,7 @@ from .models import (
Company,
Employee,
Experiment,
+ JSONFieldModel,
Manager,
Number,
RemoteEmployee,
@@ -365,6 +367,21 @@ class BasicExpressionsTests(TestCase):
Number.objects.all(), [None, None], lambda n: n.float, ordered=False
)
+ @skipUnlessDBFeature("supports_json_field")
+ def test_update_jsonfield_case_when_key_is_null(self):
+ obj = JSONFieldModel.objects.create(data={"key": None})
+ updated = JSONFieldModel.objects.update(
+ data=Case(
+ When(
+ data__key=Value(None, JSONField()),
+ then=Value({"key": "something"}, JSONField()),
+ ),
+ )
+ )
+ self.assertEqual(updated, 1)
+ obj.refresh_from_db()
+ self.assertEqual(obj.data, {"key": "something"})
+
def test_filter_with_join(self):
# F Expressions can also span joins
Company.objects.update(point_of_contact=F("ceo"))