Opened 5 months ago
Closed 5 months ago
#36440 closed Bug (duplicate)
bulk_update() on JSONField saves JSON null instead of SQL NULL
| Reported by: | Adam Johnson | Owned by: | Adam Johnson | 
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 5.2 | 
| Severity: | Release blocker | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | yes | Needs documentation: | no | 
| Needs tests: | no | Patch needs improvement: | no | 
| Easy pickings: | no | UI/UX: | no | 
Description
I have a client project with a Django model that has a JSONField and a check constraint requiring the field to either contain SQL NULL or a JSON object (via a custom database function calling PostgreSQL's jsonb_typeof). Upgrading to Django 5.2 causes a bulk_update() query on that model to start failing with IntegrityError, because the JSON null is serialized instead ('null'::json in PostgreSQL syntax).
Like #36404 and #36405, this is another bug that bisects to e306687a3a5507d59365ba9bf545010e5fd4b2a8.
The issue:
BaseExpression.resolve_expression()no longer passes thefor_saveparameter through to source expressions.- When a source expression is a 
Value,for_savebeingFalseprevents it from callingField.get_db_prep_save(): https://github.com/django/django/blob/f0a87895ffaf6532a22143b5e2e304c59b7958ae/django/db/models/expressions.py#L1170-L1173 . JSONField.get_db_prep_save()has specific behaviour forNone, ensuring it's returned as-is rather than wrapped as JSON: https://github.com/django/django/blob/main/django/db/models/fields/json.py#L110-L111- The missed call means 
Noneis wrapped as JSON null, which fails the model's check constraint. 
Patch incoming.
Change History (2)
comment:1 by , 5 months ago
| Summary: | JSON null saved instead of NULL → bulk_update() on JSONField saves JSON null instead of SQL NULL | 
|---|
comment:2 by , 5 months ago
| Resolution: | → duplicate | 
|---|---|
| Status: | assigned → closed | 
Duplicate of #36419