Opened 3 months ago
Closed 2 months ago
#36445 closed Bug (wontfix)
Value(None, output_field=JSONField()) incorrectly saves as SQL NULL in bulk_update()
Reported by: | Clifford Gama | Owned by: | Uddyan Goyal |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Simon Charette, Thomas | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
When using bulk_update()
with a Value(None, output_field=JSONField())
expression, the value is incorrectly saved as a SQL NULL
rather than a JSON null
. This behavior was temporarily fixed in 00c690efbc0b10f67924687f24a7b30397bf47d9 due to incomplete for_save
propagation during expression resolution (bug in #36419), but reappears after the proper restoration of for_save
handling in #36419.
-
tests/queries/test_bulk_update.py
diff --git a/tests/queries/test_bulk_update.py b/tests/queries/test_bulk_update.py index 480fac6784..6c553421cb 100644
a b from math import ceil 3 3 4 4 from django.core.exceptions import FieldDoesNotExist 5 5 from django.db import connection 6 from django.db.models import F 6 from django.db.models import F, Value, JSONField 7 7 from django.db.models.functions import Coalesce, Lower 8 8 from django.db.utils import IntegrityError 9 9 from django.test import TestCase, override_settings, skipUnlessDBFeature … … class BulkUpdateTests(TestCase): 315 315 sql_null_qs = JSONFieldNullable.objects.filter(json_field__isnull=True) 316 316 self.assertSequenceEqual(sql_null_qs, [obj]) 317 317 318 @skipUnlessDBFeature("supports_json_field") 319 def test_json_field_json_null_value(self): 320 obj = JSONFieldNullable.objects.create(json_field={}) 321 obj.json_field = Value(None, output_field=JSONField()) 322 JSONFieldNullable.objects.bulk_update([obj], fields=["json_field"]) 323 obj.refresh_from_db() 324 json_null_qs = JSONFieldNullable.objects.filter(json_field=None) 325 self.assertSequenceEqual(json_null_qs, [obj]) 326 318 327 def test_nullable_fk_after_related_save(self): 319 328 parent = RelatedObject.objects.create() 320 329 child = SingleObject()
Change History (13)
comment:1 by , 3 months ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 3 months ago
Description: | modified (diff) |
---|
comment:3 by , 3 months ago
Owner: | set to |
---|---|
Status: | new → assigned |
follow-up: 11 comment:4 by , 3 months ago
Now that we know this isn't a regression should we consider biting the bullet and stop trying to make Value(None, JSONField())
work by introducing a proper JSONNull
expression as described in ticket:35381#comment:3?
comment:5 by , 3 months ago
Has patch: | set |
---|
Hello this ticket was unassigned so I assigned this to myself as mentioned in the documentation. I have raised a [PR https://github.com/django/django/pull/19546] for this bug. Please review. I have tried to follow all the instructions as mentioned in the documentation. Please let me know if I missed anything.
Thanks!
comment:6 by , 3 months ago
@Simon Charette: It may not be a regression for the bulk_update
case outlined here (of which I don't fully understand the chronology), but isn't it a regression in the case I outlined in #36453 (which has been marked as a duplicate of this issue)? Code that has been working a certain way for 1-2 years is broken in 5.2.3.
comment:7 by , 3 months ago
Cc: | added |
---|
Now that we know this isn't a regression
I wasn't involved in the regression status determination, my comment was referring to this discussion and assuming it was the case. It is possible that the issue you reported in #36453 is a valid regression in Django 5.2.3 for a slightly different scenario as When
/ Case
have a variation of expression resolving than Coalesce
.
If you can write a regression test that passes for < 5.2 and fail for 5.2.3 then it is effectively a regression and closing #36453, and potentially categorizing this ticket as an issue predating 5.2, was likely a triage mistake.
comment:8 by , 3 months ago
I've made a regression test for the use case detailed in #36453.
https://github.com/thomas-mckay/django/commit/5ca2b19568b39c41248479ad4b19973fe622c438
After bisection, I've noticed that the test passes from 4.2
to 5.2.2
. It breaks in 5.2.3
and before 4.2
.
To recap:
- https://github.com/django/django/commit/5c23d9f0c32f166c81ecb6f3f01d5077a6084318 was introduced in
4.2
. Before this commit the test fails, after this commit the test passes, until5.2.3
- https://github.com/django/django/commit/6fc620b4a8e91839b93af2b52d80bdbd5f8a1fcc was introduced in
5.2.3
. After this commit the test fails again.
I've checked Value.for_save
, and it is indeed False
in 5.2.2
and True
in 5.2.3
for the Value
in the When
condition. So, I understand why #36453 may have been closed as a duplicate of this one: it sounds like the same change may be responsible. My only concern is that the bug in this ticket only covers one of the symptoms of that change (that may or may not be a regression), but not the one I'm experiencing (which I really hope is considered a regression), and that addressing this symptom will not fix the behavior that's been broken in my case. Let me know if I'm taking this ticket off-topic and I'll re-open my ticket and continue there.
comment:9 by , 3 months ago
I've tested the patch proposed by @GoyalRocks007 in comment:5. With this patch the test passes again.
comment:10 by , 3 months ago
Cc: | added |
---|
comment:11 by , 3 months ago
Replying to Simon Charette:
Now that we know this isn't a regression should we consider biting the bullet and stop trying to make
Value(None, JSONField())
work by introducing a properJSONNull
expression as described in ticket:35381#comment:3?
In light of recent reports around JSON null/SQL NULL, (the latest being #36453) I'd say yes. Would this mean marking this ticket as invalid in favour of a #35381 repurposed for the JSONNull
new feature? Or perhaps a new ticket?
comment:12 by , 3 months ago
Patch needs improvement: | set |
---|
I see that there is a growing consensus to pursue JSONNull
(ref ticket:36445#comment:4, ticket:35381#comment:10, ticket:36445#comment:11).
We should pursue this before bolting on more logic to trying to resolve the json null problem (note that I confirmed that this test in the PR has been failing since at least Django 4.1 and potentially has never worked)
comment:13 by , 2 months ago
Resolution: | → wontfix |
---|---|
Status: | assigned → closed |
#35381 was repurposed so this ticket is being closed as wontfix
following previous conversations.
Thank you for the ticket