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 side-effects 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 side-effect 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 , 2 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