Skip to content

Commit 1d89691

Browse files
cliffordgamasarahboyce
authored andcommitted
[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 c1fa3fd. 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 104cbfd from main.
1 parent 4de4edf commit 1d89691

3 files changed

Lines changed: 32 additions & 0 deletions

File tree

django/db/models/expressions.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,17 @@ def get_source_expressions(self):
15881588
def set_source_expressions(self, exprs):
15891589
self.condition, self.result = exprs
15901590

1591+
def resolve_expression(
1592+
self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False
1593+
):
1594+
c = super().resolve_expression(query, allow_joins, reuse, summarize, for_save)
1595+
if for_save and c.condition is not None:
1596+
# Resolve condition with for_save=False, since it's used as a filter.
1597+
c.condition = self.condition.resolve_expression(
1598+
query, allow_joins, reuse, summarize, for_save=False
1599+
)
1600+
return c
1601+
15911602
def get_source_fields(self):
15921603
# We're only interested in the fields of the result expressions.
15931604
return [self.result._output_field_or_none]

docs/releases/5.2.4.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ Bugfixes
1212
* Fixed a regression in Django 5.2.2 where :meth:`HttpRequest.get_preferred_type()
1313
<django.http.HttpRequest.get_preferred_type>` incorrectly preferred more
1414
specific media types with a lower quality (:ticket:`36447`).
15+
16+
* Fixed a regression in Django 5.2.3 where ``Value(None, JSONField())`` used in
17+
a :class:`~django.db.models.expressions.When` condition was incorrectly
18+
serialized as SQL ``NULL`` instead of JSON ``null`` (:ticket:`36453`).

tests/expressions/tests.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
FloatField,
3030
Func,
3131
IntegerField,
32+
JSONField,
3233
Max,
3334
Min,
3435
Model,
@@ -81,6 +82,7 @@
8182
Company,
8283
Employee,
8384
Experiment,
85+
JSONFieldModel,
8486
Manager,
8587
Number,
8688
RemoteEmployee,
@@ -365,6 +367,21 @@ def test_update_with_none(self):
365367
Number.objects.all(), [None, None], lambda n: n.float, ordered=False
366368
)
367369

370+
@skipUnlessDBFeature("supports_json_field")
371+
def test_update_jsonfield_case_when_key_is_null(self):
372+
obj = JSONFieldModel.objects.create(data={"key": None})
373+
updated = JSONFieldModel.objects.update(
374+
data=Case(
375+
When(
376+
data__key=Value(None, JSONField()),
377+
then=Value({"key": "something"}, JSONField()),
378+
),
379+
)
380+
)
381+
self.assertEqual(updated, 1)
382+
obj.refresh_from_db()
383+
self.assertEqual(obj.data, {"key": "something"})
384+
368385
def test_filter_with_join(self):
369386
# F Expressions can also span joins
370387
Company.objects.update(point_of_contact=F("ceo"))

0 commit comments

Comments
 (0)