#33820 closed Bug (fixed)
Querying "null" on key transforms for JSONField returns wrong results on SQLite.
| Reported by: | Johnny Metz | Owned by: | Mariusz Felisiak |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 4.0 |
| Severity: | Release blocker | Keywords: | JSONField |
| Cc: | Matthew Cornell, Sage Abdullah | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Let's say I have a Django model with a JSONField:
class Event(models.Model):
data = models.JSONField()
And I create the following objects:
event1 = Event.objects.create(data={"key": None})
event2 = Event.objects.create(data={"key": "null"})
In Django 3.2.13, the following queries return some results:
Event.objects.filter(data__key=Value("null"))
# [event1]
Event.objects.filter(data__key="null")
# [event2]
In Django 4.0.5, the same queries return different results:
Event.objects.filter(data__key=Value("null"))
# [event1, event2]
Event.objects.filter(data__key="null")
# [event1, event2]
The Django docs aren't clear which results are correct. I would lean towards the v3 results.
I'm happy to work on a patch if people think this is a bug in v4.
Attachments (1)
Change History (12)
comment:1 by , 3 years ago
| Cc: | added |
|---|---|
| Severity: | Normal → Release blocker |
| Summary: | Querying null in JSONField is different between 3.2 and 4.0 → Querying "null" on key transforms for JSONField returns wrong results on SQLite. |
| Triage Stage: | Unreviewed → Accepted |
comment:2 by , 3 years ago
Seems like a type-juggling routine introduced in 4.0.0
I am totally into type-juggling but this case, and actually blocking issue is a great example of the general confusion that a seemingly *simplification* - may lead to hold back on tech dev.
TL;DR:
- consider removing type juggling
- keep principles up, regarding data type comparison
by , 3 years ago
| Attachment: | regression-tests-33820.diff added |
|---|
comment:3 by , 3 years ago
I tried to fix this few times in the last two weeks, unfortunately, I don't see a proper way to distinguish between {"x": "null"} and {"x": NULL} extracted from the JSON field (the same for boolean values). Mainly due to the lack of proper database types in SQLite. In 71ec102b01fcc85acae3819426a4e02ef423b0fa we tried to use
CASE WHEN JSON_TYPE("model"."json_field", $."key") IN ('null', 'false', 'true') THEN JSON_TYPE("model"."json_field", $."key") ELSE JSON_EXTRACT("model"."json_field", $."key") END
which fixed #32483 but also introduced this regression because for both NULL and "null" it returns 'null'.
Quo vadis? 🤷 We have two options:
- document this as a SQLite caveat,
- revert 71ec102b01fcc85acae3819426a4e02ef423b0fa and reintroduce another SQLite caveat.
follow-up: 5 comment:4 by , 3 years ago
document this as a SQLite caveat,
I'd go with this. I think storing "null" is quite niche, and easily worked around.
comment:5 by , 3 years ago
Replying to Carlton Gibson:
I'd go with this. I think storing
"null"is quite niche, and easily worked around.
Just to be clear, this issue is for all three "true", "false", and "null".
comment:6 by , 3 years ago
Sure, yes. My feeling is that it's better to resolve #32483, which was 71ec102b01fcc85acae3819426a4e02ef423b0fa. Most times I want True/False/None, and I can serialise those if I need to. (That's just a +1 towards option 1 in response to the What to do?)
comment:7 by , 3 years ago
| Cc: | added |
|---|
Thanks for the report. Regression in 71ec102b01fcc85acae3819426a4e02ef423b0fa. This is also inconsistent with other backends.