mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #30335, #29139 -- Fixed crash when ordering or aggregating over a nested JSONField key transform.
This commit is contained in:
		| @@ -14,6 +14,7 @@ from django.db.models.sql.query import Query, get_order_dir | ||||
| from django.db.transaction import TransactionManagementError | ||||
| from django.db.utils import DatabaseError, NotSupportedError | ||||
| from django.utils.deprecation import RemovedInDjango31Warning | ||||
| from django.utils.hashable import make_hashable | ||||
|  | ||||
| FORCE = object() | ||||
|  | ||||
| @@ -126,9 +127,10 @@ class SQLCompiler: | ||||
|  | ||||
|         for expr in expressions: | ||||
|             sql, params = self.compile(expr) | ||||
|             if (sql, tuple(params)) not in seen: | ||||
|             params_hash = make_hashable(params) | ||||
|             if (sql, params_hash) not in seen: | ||||
|                 result.append((sql, params)) | ||||
|                 seen.add((sql, tuple(params))) | ||||
|                 seen.add((sql, params_hash)) | ||||
|         return result | ||||
|  | ||||
|     def collapse_group_by(self, expressions, having): | ||||
| @@ -352,9 +354,10 @@ class SQLCompiler: | ||||
|             # is refactored into expressions, then we can check each part as we | ||||
|             # generate it. | ||||
|             without_ordering = self.ordering_parts.search(sql).group(1) | ||||
|             if (without_ordering, tuple(params)) in seen: | ||||
|             params_hash = make_hashable(params) | ||||
|             if (without_ordering, params_hash) in seen: | ||||
|                 continue | ||||
|             seen.add((without_ordering, tuple(params))) | ||||
|             seen.add((without_ordering, params_hash)) | ||||
|             result.append((resolved, (sql, params, is_ref))) | ||||
|         return result | ||||
|  | ||||
|   | ||||
| @@ -33,3 +33,8 @@ Bugfixes | ||||
| * Reverted an optimization in Django 2.2 (:ticket:`29725`) that caused the | ||||
|   inconsistent behavior of ``count()`` and ``exists()`` on a reverse | ||||
|   many-to-many relationship with a custom manager (:ticket:`30325`). | ||||
|  | ||||
| * Fixed a regression in Django 2.2 where | ||||
|   :class:`~django.core.paginator.Paginator` crashed when ``object_list`` was | ||||
|   a queryset ordered or aggregated over a nested ``JSONField`` key transform | ||||
|   (:ticket:`30335`). | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| import datetime | ||||
| import operator | ||||
| import uuid | ||||
| from decimal import Decimal | ||||
|  | ||||
| from django.core import checks, exceptions, serializers | ||||
| from django.core.serializers.json import DjangoJSONEncoder | ||||
| from django.db.models import Q | ||||
| from django.db.models import Count, Q | ||||
| from django.forms import CharField, Form, widgets | ||||
| from django.test.utils import isolate_apps | ||||
| from django.utils.html import escape | ||||
| @@ -15,6 +16,7 @@ from .models import JSONModel, PostgreSQLModel | ||||
| try: | ||||
|     from django.contrib.postgres import forms | ||||
|     from django.contrib.postgres.fields import JSONField | ||||
|     from django.contrib.postgres.fields.jsonb import KeyTextTransform, KeyTransform | ||||
| except ImportError: | ||||
|     pass | ||||
|  | ||||
| @@ -162,6 +164,27 @@ class TestQuerying(PostgreSQLTestCase): | ||||
|         query = JSONModel.objects.filter(field__name__isnull=False).order_by('field__ord') | ||||
|         self.assertSequenceEqual(query, [objs[4], objs[2], objs[3], objs[1], objs[0]]) | ||||
|  | ||||
|     def test_ordering_grouping_by_key_transform(self): | ||||
|         base_qs = JSONModel.objects.filter(field__d__0__isnull=False) | ||||
|         for qs in ( | ||||
|             base_qs.order_by('field__d__0'), | ||||
|             base_qs.annotate(key=KeyTransform('0', KeyTransform('d', 'field'))).order_by('key'), | ||||
|         ): | ||||
|             self.assertSequenceEqual(qs, [self.objs[8]]) | ||||
|         qs = JSONModel.objects.filter(field__isnull=False) | ||||
|         self.assertQuerysetEqual( | ||||
|             qs.values('field__d__0').annotate(count=Count('field__d__0')).order_by('count'), | ||||
|             [1, 10], | ||||
|             operator.itemgetter('count'), | ||||
|         ) | ||||
|         self.assertQuerysetEqual( | ||||
|             qs.filter(field__isnull=False).annotate( | ||||
|                 key=KeyTextTransform('f', KeyTransform('1', KeyTransform('d', 'field'))), | ||||
|             ).values('key').annotate(count=Count('key')).order_by('count'), | ||||
|             [(None, 0), ('g', 1)], | ||||
|             operator.itemgetter('key', 'count'), | ||||
|         ) | ||||
|  | ||||
|     def test_deep_values(self): | ||||
|         query = JSONModel.objects.values_list('field__k__l') | ||||
|         self.assertSequenceEqual( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user