Fixed #32203 -- Fixed QuerySet.values()/values_list() crash on key transforms with non-string values on SQLite.

Thanks Gordon Wrigley for the report.
This commit is contained in:
sage 2020-11-18 11:50:06 +07:00 committed by Mariusz Felisiak
parent 7408c4cd15
commit fe6e582421
3 changed files with 13 additions and 0 deletions

View File

@ -75,6 +75,10 @@ class JSONField(CheckFieldDefaultMixin, Field):
def from_db_value(self, value, expression, connection): def from_db_value(self, value, expression, connection):
if value is None: if value is None:
return value return value
# Some backends (SQLite at least) extract non-string values in their
# SQL datatypes.
if isinstance(expression, KeyTransform) and not isinstance(value, str):
return value
try: try:
return json.loads(value, cls=self.decoder) return json.loads(value, cls=self.decoder)
except json.JSONDecodeError: except json.JSONDecodeError:

View File

@ -28,3 +28,7 @@ Bugfixes
* Fixed a regression in Django 3.1 that caused suppressing connection errors * Fixed a regression in Django 3.1 that caused suppressing connection errors
when :class:`~django.db.models.JSONField` is used on SQLite when :class:`~django.db.models.JSONField` is used on SQLite
(:ticket:`32224`). (:ticket:`32224`).
* Fixed a crash on SQLite, when ``QuerySet.values()/values_list()`` contained
key transforms for :class:`~django.db.models.JSONField` returning non-string
primitive values (:ticket:`32203`).

View File

@ -277,6 +277,7 @@ class TestQuerying(TestCase):
'k': {'l': 'm'}, 'k': {'l': 'm'},
'n': [None], 'n': [None],
'o': '"quoted"', 'o': '"quoted"',
'p': 4.2,
}, },
[1, [2]], [1, [2]],
{'k': True, 'l': False, 'foo': 'bax'}, {'k': True, 'l': False, 'foo': 'bax'},
@ -753,10 +754,14 @@ class TestQuerying(TestCase):
qs = NullableJSONModel.objects.filter(value__h=True) qs = NullableJSONModel.objects.filter(value__h=True)
tests = [ tests = [
('value__a', 'b'), ('value__a', 'b'),
('value__c', 14),
('value__d', ['e', {'f': 'g'}]), ('value__d', ['e', {'f': 'g'}]),
('value__h', True),
('value__i', False),
('value__j', None), ('value__j', None),
('value__k', {'l': 'm'}), ('value__k', {'l': 'm'}),
('value__n', [None]), ('value__n', [None]),
('value__p', 4.2),
] ]
for lookup, expected in tests: for lookup, expected in tests:
with self.subTest(lookup=lookup): with self.subTest(lookup=lookup):