[1.11.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 3deda1f680
commit 473c526b1b
6 changed files with 49 additions and 2 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(object): class KeyTransformFactory(object):

View File

@ -107,7 +107,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`).

View File

@ -26,6 +26,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

@ -5,6 +5,7 @@ import json
from django.core import exceptions, serializers from django.core import 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, modify_settings from django.test.utils import CaptureQueriesContext, modify_settings
@ -14,6 +15,7 @@ from .models import HStoreModel
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
@ -121,6 +123,13 @@ class TestQuerying(HStoreTestCase):
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

@ -7,6 +7,9 @@ from decimal import Decimal
from django.core import exceptions, serializers from django.core import 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 F
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 import skipUnlessDBFeature from django.test import skipUnlessDBFeature
from django.test.utils import CaptureQueriesContext from django.test.utils import CaptureQueriesContext
@ -18,6 +21,7 @@ from .models import JSONModel
try: try:
from django.contrib.postgres import forms from django.contrib.postgres import forms
from django.contrib.postgres.fields import JSONField from django.contrib.postgres.fields import JSONField
from django.contrib.postgres.fields.jsonb import KeyTransform
except ImportError: except ImportError:
pass pass
@ -147,6 +151,24 @@ class TestQuerying(PostgreSQLTestCase):
[self.objs[0]] [self.objs[0]]
) )
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'),
).annotate(
chain=KeyTransform('0', 'key'),
expr=KeyTransform('0', Cast('key', JSONField())),
).filter(chain=F('expr')),
[self.objs[8]],
)
def test_isnull_key(self): def test_isnull_key(self):
# key__isnull works the same as has_key='key'. # key__isnull works the same as has_key='key'.
self.assertSequenceEqual( self.assertSequenceEqual(