Fixed #32213 -- Ensured KeyTransform values are properly quoted on SQLite#20487
Fixed #32213 -- Ensured KeyTransform values are properly quoted on SQLite#20487VIZZARD-X wants to merge 1 commit intodjango:mainfrom
Conversation
6171394 to
51be479
Compare
charettes
left a comment
There was a problem hiding this comment.
Have we considered implementing KeyTransform.select_format to behave differently on SQLite instead to avoid bi-directionally coupling JSONField with it?
select_format is only called when the expression is part of the SELECT clause so it could be used to generate proper SQL (e.g. adapt quoting) so JSONField.from_db_value can remain unchanged.
This would be a better solution in my opinion as isolates the SQLite specialization to KeyTransform.
| class Ticket32213Model(models.Model): | ||
| data = models.JSONField() |
There was a problem hiding this comment.
Avoid creating models / tables and ticket classes for each tickets; reuse the existing ones.
django/db/models/fields/json.py
Outdated
| if value not in ("true", "false", "null") and not value.startswith( | ||
| ("{", "[") | ||
| ): | ||
| return value |
There was a problem hiding this comment.
What about top level integers and strings?
51be479 to
0ddb14b
Compare
|
I've updated the PR based on your feedback:
Ready for another look 👍 |
0ddb14b to
75c8c04
Compare
75c8c04 to
aeb4485
Compare
| f"ELSE JSON_EXTRACT({lhs}, %s) END", | ||
| args * 3, | ||
| ) | ||
| return super().select_format(compiler, sql, params) |
There was a problem hiding this comment.
I'm pretty sure this won't work, see the entire discussion in ticket-33820 (especially this comment).
There was a problem hiding this comment.
I reviewed comment:3 on ticket-33820. The key difference here is that this implementation explicitly guards WHEN 'text' first.
This forces JSON_QUOTE on strings (preserving "null" as '"null"'), while letting primitives fall through to the ELSE block as raw values. The updated test confirms this successfully disambiguates conflicting pairs like "null" vs null and "123" vs 123.
aeb4485 to
7940481
Compare
7940481 to
9405f3f
Compare
9405f3f to
0a3cdff
Compare
|
@charettes I've updated the implementation to use @felixxm regarding the type preservation concerns: I've added a regression test to Ready for a review when you are free... |
📊 Coverage Report for Changed FilesNote: Missing lines are warnings only. Some lines may not be covered by SQLite tests as they are database-specific. For more information about code coverage on pull requests, see the contributing documentation. |
Trac ticket number
ticket-32213
Branch description
On SQLite,
KeyTransformlookups (e.g.,.values('data__key')) extract values as raw strings without quotes. This causesjson.loadsto misinterpret them (e.g., string"123"becomes integer123, and string"value"is returned asvaluewithout quotes).The solution implements
KeyTransform.select_formatto apply aCASE WHEN JSON_TYPEguard at the SQL level, which explicitly appliesJSON_QUOTEto text values while allowing primitives to fall through naturally. This ensures strict type preservation for edge cases like"null"vsnullwithout introducing coupling inJSONField.from_db_value.Test:
A regression test
test_json_key_transform_type_preservation_sqlitewas added to the existingtest_jsonfield.pywhich checks thatstring,integer,boolean, andnulltypes remain distinct after extraction.Checklist
mainbranch.