mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #30315 -- Fixed crash of ArrayAgg and StringAgg with ordering when used in Subquery.
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							b2790f74d4
						
					
				
				
					commit
					a3f91891d2
				
			| @@ -33,6 +33,12 @@ class OrderableAggMixin: | ||||
|             return sql, sql_params + ordering_params | ||||
|         return super().as_sql(compiler, connection, ordering='') | ||||
|  | ||||
|     def set_source_expressions(self, exprs): | ||||
|         # Extract the ordering expressions because ORDER BY clause is handled | ||||
|         # in a custom way. | ||||
|         self.ordering = exprs[self._get_ordering_expressions_index():] | ||||
|         return super().set_source_expressions(exprs[:self._get_ordering_expressions_index()]) | ||||
|  | ||||
|     def get_source_expressions(self): | ||||
|         return self.source_expressions + self.ordering | ||||
|  | ||||
|   | ||||
| @@ -21,3 +21,7 @@ Bugfixes | ||||
|  | ||||
| * Fixed a regression in Django 2.2 where auto-reloader doesn't detect changes | ||||
|   in ``manage.py`` file when using ``StatReloader`` (:ticket:`30479`). | ||||
|  | ||||
| * Fixed crash of :class:`~django.contrib.postgres.aggregates.ArrayAgg` and | ||||
|   :class:`~django.contrib.postgres.aggregates.StringAgg` with ``ordering`` | ||||
|   argument when used in a ``Subquery`` (:ticket:`30315`). | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| import json | ||||
|  | ||||
| from django.db.models.expressions import F, Value | ||||
| from django.db.models.functions import Concat, Substr | ||||
| from django.db.models import CharField | ||||
| from django.db.models.expressions import F, OuterRef, Subquery, Value | ||||
| from django.db.models.functions import Cast, Concat, Substr | ||||
| from django.test.utils import Approximate | ||||
|  | ||||
| from . import PostgreSQLTestCase | ||||
| @@ -202,6 +203,36 @@ class TestGeneralAggregate(PostgreSQLTestCase): | ||||
|         values = AggregateTestModel.objects.none().aggregate(jsonagg=JSONBAgg('integer_field')) | ||||
|         self.assertEqual(values, json.loads('{"jsonagg": []}')) | ||||
|  | ||||
|     def test_string_agg_array_agg_ordering_in_subquery(self): | ||||
|         stats = [] | ||||
|         for i, agg in enumerate(AggregateTestModel.objects.order_by('char_field')): | ||||
|             stats.append(StatTestModel(related_field=agg, int1=i, int2=i + 1)) | ||||
|             stats.append(StatTestModel(related_field=agg, int1=i + 1, int2=i)) | ||||
|         StatTestModel.objects.bulk_create(stats) | ||||
|  | ||||
|         for aggregate, expected_result in ( | ||||
|             ( | ||||
|                 ArrayAgg('stattestmodel__int1', ordering='-stattestmodel__int2'), | ||||
|                 [('Foo1', [0, 1]), ('Foo2', [1, 2]), ('Foo3', [2, 3]), ('Foo4', [3, 4])], | ||||
|             ), | ||||
|             ( | ||||
|                 StringAgg( | ||||
|                     Cast('stattestmodel__int1', CharField()), | ||||
|                     delimiter=';', | ||||
|                     ordering='-stattestmodel__int2', | ||||
|                 ), | ||||
|                 [('Foo1', '0;1'), ('Foo2', '1;2'), ('Foo3', '2;3'), ('Foo4', '3;4')], | ||||
|             ), | ||||
|         ): | ||||
|             with self.subTest(aggregate=aggregate.__class__.__name__): | ||||
|                 subquery = AggregateTestModel.objects.filter( | ||||
|                     pk=OuterRef('pk'), | ||||
|                 ).annotate(agg=aggregate).values('agg') | ||||
|                 values = AggregateTestModel.objects.annotate( | ||||
|                     agg=Subquery(subquery), | ||||
|                 ).order_by('char_field').values_list('char_field', 'agg') | ||||
|                 self.assertEqual(list(values), expected_result) | ||||
|  | ||||
|  | ||||
| class TestAggregateDistinct(PostgreSQLTestCase): | ||||
|     @classmethod | ||||
|   | ||||
		Reference in New Issue
	
	Block a user