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() ` 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"))