[Django] #36453: 5.2.3 introduces a regression when using `Value(None, output_field=JSONField()` in a `When` clause.

11 views
Skip to first unread message

Django

unread,
Jun 10, 2025, 6:04:51 PMJun 10
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Type: Bug
Status: new | Component: Database
| layer (models, ORM)
Version: 5.2 | Severity: Normal
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
We've tried to upgrade to 5.2.3 and several of our tests started failing.
We've pinpointed the problem to one query which uses `Value(None,
output_field=JSONField()` in a `When` clause. Here's a minimal
reproducible example (with a `WHERE` clause too, to highlight the
difference in behavior):

{{{
from django.db import connection
from django.db.models import (
BigIntegerField,
Case,
F,
JSONField,
Model,
Value,
When,
)
from django.db.models.functions import Cast


class Foo(Model):
bar = BigIntegerField(blank=True, null=True)
json_field = JSONField(blank=True, null=True)


if __name__ == '__main__':
Foo.objects.filter(
json_field__key_1=Value(None, output_field=JSONField())
).update(
bar=Case(
When(
json_field__key_2=Value(None, output_field=JSONField()),
then=None
),
default=Cast(F('json_field__key_2'), BigIntegerField()),
output_field=BigIntegerField(),
),
)

print(connection.queries[-1]['sql'])
}}}

We ran this code with 5.2.2 (with this version our test suite passes) and
5.2.3 (with this version our test suite fails) and got this:
{{{
-- Generated with Django 5.2.2
UPDATE "polls_foo"
SET "bar" = CASE WHEN (
("polls_foo"."json_field" -> 'key_2') = 'null'::jsonb -- JSON
"null"
)
THEN NULL
ELSE (("polls_foo"."json_field" -> 'key_2'))::bigint
END
WHERE ("polls_foo"."json_field" -> 'key_1') = 'null'::jsonb;

-- Generated with Django 5.2.3
UPDATE "polls_foo"
SET "bar" = CASE WHEN (
("polls_foo"."json_field" -> 'key_2') = NULL -- SQL NULL
)
THEN NULL
ELSE (("polls_foo"."json_field" -> 'key_2'))::bigint
END
WHERE ("polls_foo"."json_field" -> 'key_1') = 'null'::jsonb;
}}}

Notice how the `WHEN` clause differs, but the `WHERE` clause stays the
same, despite both using the same `Value(None, output_field=JSONField())`
syntax.
--
Ticket URL: <https://code.djangoproject.com/ticket/36453>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jun 10, 2025, 6:07:15 PMJun 10
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Description changed by Thomas:

Old description:
New description:
Edit: If that makes any difference, we're using PostgreSQL as a backend.

--
--
Ticket URL: <https://code.djangoproject.com/ticket/36453#comment:1>

Django

unread,
Jun 10, 2025, 6:16:33 PMJun 10
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: (none)
Type: Bug | Status: closed
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution: duplicate
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by David Sanders):

* resolution: => duplicate
* status: new => closed

Comment:

Duplicate of #36445 👍
--
Ticket URL: <https://code.djangoproject.com/ticket/36453#comment:2>

Django

unread,
Jun 10, 2025, 7:20:59 PMJun 10
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: (none)
Type: Bug | Status: closed
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution: duplicate
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Thomas):

I guess this was closed as duplicate because the cause might be the same,
but then I don't understand how the other ticket claims it isn't a
regression. The code I posted has been working since 4.x at least. It only
breaks with 5.2.3 (released June 10th), which I guess was released with a
known bug (#36445, June 6th).
--
Ticket URL: <https://code.djangoproject.com/ticket/36453#comment:3>

Django

unread,
Jun 12, 2025, 6:02:39 AMJun 12
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Clifford Gama):

* resolution: duplicate =>
* severity: Normal => Release blocker
* stage: Unreviewed => Accepted
* status: closed => new

Comment:

This is indeed a regression in c1fa3fdd040718356e5a3b9a0fe699d73f47a940.

The problem is that we are now passing on `for_save` to `Case`'s source
expressions, and resolving `When.condition` with `for_save=True`.

The issue is related to #36445 in that they both expose problems related
to the use of `Value(None, JSONField())` to mean `JSON null` and None to
mean `NULL`, and how that is implemented depending on whether
`JSONFIeld.get_db_prep_save` is called. I think these set of tickets
should be an argument in favour of introducing a `JSONNull` value as
outlined in ticket:35381#comment:5.
--
Ticket URL: <https://code.djangoproject.com/ticket/36453#comment:4>

Django

unread,
Jun 12, 2025, 6:18:12 AMJun 12
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Clifford Gama):

* has_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/36453#comment:5>

Django

unread,
Jun 12, 2025, 7:30:33 AMJun 12
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Thomas):

Thank you for the super fast patch, @Clifford Gama.
--
Ticket URL: <https://code.djangoproject.com/ticket/36453#comment:6>

Django

unread,
Jun 12, 2025, 8:33:45 AMJun 12
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: Clifford
| Gama
Type: Bug | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* owner: (none) => Clifford Gama
* status: new => assigned

--
Ticket URL: <https://code.djangoproject.com/ticket/36453#comment:7>

Django

unread,
Jun 13, 2025, 7:11:32 AMJun 13
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: Clifford
| Gama
Type: Bug | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* stage: Accepted => Ready for checkin

--
Ticket URL: <https://code.djangoproject.com/ticket/36453#comment:8>

Django

unread,
Jun 16, 2025, 4:40:41 AMJun 16
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: Clifford
| Gama
Type: Bug | Status: closed
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution: fixed
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce <42296566+sarahboyce@…>):

* resolution: => fixed
* status: assigned => closed

Comment:

In [changeset:"104cbfd44b9eff010daf0ef0e1ce434385855b13" 104cbfd4]:
{{{#!CommitTicketReference repository=""
revision="104cbfd44b9eff010daf0ef0e1ce434385855b13"
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+...@users.noreply.github.com>
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36453#comment:9>

Django

unread,
Jun 16, 2025, 4:42:01 AMJun 16
to django-...@googlegroups.com
#36453: 5.2.3 introduces a regression when using `Value(None,
output_field=JSONField()` in a `When` clause.
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: Clifford
| Gama
Type: Bug | Status: closed
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution: fixed
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"1d89691c7481fbcef6a7bc396e41a651372c1cf3" 1d89691]:
{{{#!CommitTicketReference repository=""
revision="1d89691c7481fbcef6a7bc396e41a651372c1cf3"
[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+...@users.noreply.github.com>

Backport of 104cbfd44b9eff010daf0ef0e1ce434385855b13 from main.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36453#comment:10>
Reply all
Reply to author
Forward
0 new messages