1
0
mirror of https://github.com/django/django.git synced 2025-07-12 13:49:11 +00:00

[2.2.x] Fixed #30672 -- Fixed crash of JSONField/HStoreField key transforms on expressions with params.

Regression in 4f5b58f5cd3c57fee9972ab074f8dc6895d8f387.

Thanks Florian Apolloner for the report and helping with tests.

Backport of 1f8382d34d54061eddc41df6994e20ee38c60907 from master.
This commit is contained in:
Mariusz Felisiak 2019-08-14 15:25:35 +02:00
parent be4a2a0358
commit 52a7759a49
8 changed files with 68 additions and 3 deletions

View File

@ -86,7 +86,7 @@ class KeyTransform(Transform):
def as_sql(self, compiler, connection): def as_sql(self, compiler, connection):
lhs, params = compiler.compile(self.lhs) lhs, params = compiler.compile(self.lhs)
return '(%s -> %%s)' % lhs, [self.key_name] + params return '(%s -> %%s)' % lhs, params + [self.key_name]
class KeyTransformFactory: class KeyTransformFactory:

View File

@ -112,7 +112,7 @@ class KeyTransform(Transform):
lookup = int(self.key_name) lookup = int(self.key_name)
except ValueError: except ValueError:
lookup = self.key_name lookup = self.key_name
return '(%s %s %%s)' % (lhs, self.operator), [lookup] + params return '(%s %s %%s)' % (lhs, self.operator), params + [lookup]
class KeyTextTransform(KeyTransform): class KeyTextTransform(KeyTransform):

15
docs/releases/1.11.24.txt Normal file
View File

@ -0,0 +1,15 @@
============================
Django 1.11.24 release notes
============================
*Expected September 2, 2019*
Django 1.11.24 fixes a regression in 1.11.23.
Bugfixes
========
* Fixed crash of ``KeyTransform()`` for
:class:`~django.contrib.postgres.fields.JSONField` and
:class:`~django.contrib.postgres.fields.HStoreField` when using on
expressions with params (:ticket:`30672`).

15
docs/releases/2.1.12.txt Normal file
View File

@ -0,0 +1,15 @@
===========================
Django 2.1.12 release notes
===========================
*Expected September 2, 2019*
Django 2.1.12 fixes a regression in 2.1.11.
Bugfixes
========
* Fixed crash of ``KeyTransform()`` for
:class:`~django.contrib.postgres.fields.JSONField` and
:class:`~django.contrib.postgres.fields.HStoreField` when using on
expressions with params (:ticket:`30672`).

View File

@ -12,3 +12,8 @@ Bugfixes
* Relaxed the system check added in Django 2.2 for models to reallow use of the * Relaxed the system check added in Django 2.2 for models to reallow use of the
same ``db_table`` by multiple models when database routers are installed same ``db_table`` by multiple models when database routers are installed
(:ticket:`30673`). (:ticket:`30673`).
* Fixed crash of ``KeyTransform()`` for
:class:`~django.contrib.postgres.fields.JSONField` and
:class:`~django.contrib.postgres.fields.HStoreField` when using on
expressions with params (:ticket:`30672`).

View File

@ -37,6 +37,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
2.1.12
2.1.11 2.1.11
2.1.10 2.1.10
2.1.9 2.1.9
@ -75,6 +76,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
1.11.24
1.11.23 1.11.23
1.11.22 1.11.22
1.11.21 1.11.21

View File

@ -2,6 +2,7 @@ import json
from django.core import checks, exceptions, serializers from django.core import checks, exceptions, serializers
from django.db import connection from django.db import connection
from django.db.models.expressions import RawSQL
from django.forms import Form from django.forms import Form
from django.test.utils import CaptureQueriesContext, isolate_apps from django.test.utils import CaptureQueriesContext, isolate_apps
@ -11,6 +12,7 @@ from .models import HStoreModel, PostgreSQLModel
try: try:
from django.contrib.postgres import forms from django.contrib.postgres import forms
from django.contrib.postgres.fields import HStoreField from django.contrib.postgres.fields import HStoreField
from django.contrib.postgres.fields.hstore import KeyTransform
from django.contrib.postgres.validators import KeysValidator from django.contrib.postgres.validators import KeysValidator
except ImportError: except ImportError:
pass pass
@ -127,6 +129,13 @@ class TestQuerying(PostgreSQLTestCase):
self.objs[:2] self.objs[:2]
) )
def test_key_transform_raw_expression(self):
expr = RawSQL('%s::hstore', ['x => b, y => c'])
self.assertSequenceEqual(
HStoreModel.objects.filter(field__a=KeyTransform('x', expr)),
self.objs[:2]
)
def test_keys(self): def test_keys(self):
self.assertSequenceEqual( self.assertSequenceEqual(
HStoreModel.objects.filter(field__keys=['a']), HStoreModel.objects.filter(field__keys=['a']),

View File

@ -6,7 +6,9 @@ from decimal import Decimal
from django.core import checks, exceptions, serializers from django.core import checks, exceptions, serializers
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from django.db import connection from django.db import connection
from django.db.models import Count, Q from django.db.models import Count, F, Q
from django.db.models.expressions import RawSQL
from django.db.models.functions import Cast
from django.forms import CharField, Form, widgets from django.forms import CharField, Form, widgets
from django.test.utils import CaptureQueriesContext, isolate_apps from django.test.utils import CaptureQueriesContext, isolate_apps
from django.utils.html import escape from django.utils.html import escape
@ -177,6 +179,23 @@ class TestQuerying(PostgreSQLTestCase):
operator.itemgetter('key', 'count'), operator.itemgetter('key', 'count'),
) )
def test_key_transform_raw_expression(self):
expr = RawSQL('%s::jsonb', ['{"x": "bar"}'])
self.assertSequenceEqual(
JSONModel.objects.filter(field__foo=KeyTransform('x', expr)),
[self.objs[-1]],
)
def test_key_transform_expression(self):
self.assertSequenceEqual(
JSONModel.objects.filter(field__d__0__isnull=False).annotate(
key=KeyTransform('d', 'field'),
chain=KeyTransform('0', 'key'),
expr=KeyTransform('0', Cast('key', JSONField())),
).filter(chain=F('expr')),
[self.objs[8]],
)
def test_deep_values(self): def test_deep_values(self):
query = JSONModel.objects.values_list('field__k__l') query = JSONModel.objects.values_list('field__k__l')
self.assertSequenceEqual( self.assertSequenceEqual(