mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[3.2.x] Fixed #32478 -- Included nested columns referenced by subqueries in GROUP BY on aggregations.
Regression infb3f034f1c. Refs #31094, #31150. Thanks Igor Pejic for the report. Backport of277eea8fccfrom master
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							543171873f
						
					
				
				
					commit
					7a6ca01f4e
				
			| @@ -1127,6 +1127,9 @@ class Subquery(Expression): | ||||
|     def external_aliases(self): | ||||
|         return self.query.external_aliases | ||||
|  | ||||
|     def get_external_cols(self): | ||||
|         return self.query.get_external_cols() | ||||
|  | ||||
|     def as_sql(self, compiler, connection, template=None, query=None, **extra_context): | ||||
|         connection.ops.check_expression_support(self) | ||||
|         template_params = {**self.extra, **extra_context} | ||||
| @@ -1141,7 +1144,7 @@ class Subquery(Expression): | ||||
|     def get_group_by_cols(self, alias=None): | ||||
|         if alias: | ||||
|             return [Ref(alias, self)] | ||||
|         external_cols = self.query.get_external_cols() | ||||
|         external_cols = self.get_external_cols() | ||||
|         if any(col.possibly_multivalued for col in external_cols): | ||||
|             return [self] | ||||
|         return external_cols | ||||
|   | ||||
| @@ -1075,7 +1075,7 @@ class Query(BaseExpression): | ||||
|     def get_external_cols(self): | ||||
|         exprs = chain(self.annotations.values(), self.where.children) | ||||
|         return [ | ||||
|             col for col in self._gen_cols(exprs) | ||||
|             col for col in self._gen_cols(exprs, include_external=True) | ||||
|             if col.alias in self.external_aliases | ||||
|         ] | ||||
|  | ||||
| @@ -1710,12 +1710,17 @@ class Query(BaseExpression): | ||||
|         return targets, joins[-1], joins | ||||
|  | ||||
|     @classmethod | ||||
|     def _gen_cols(cls, exprs): | ||||
|     def _gen_cols(cls, exprs, include_external=False): | ||||
|         for expr in exprs: | ||||
|             if isinstance(expr, Col): | ||||
|                 yield expr | ||||
|             elif include_external and callable(getattr(expr, 'get_external_cols', None)): | ||||
|                 yield from expr.get_external_cols() | ||||
|             else: | ||||
|                 yield from cls._gen_cols(expr.get_source_expressions()) | ||||
|                 yield from cls._gen_cols( | ||||
|                     expr.get_source_expressions(), | ||||
|                     include_external=include_external, | ||||
|                 ) | ||||
|  | ||||
|     @classmethod | ||||
|     def _gen_col_aliases(cls, exprs): | ||||
|   | ||||
| @@ -1311,6 +1311,21 @@ class AggregateTestCase(TestCase): | ||||
|         #     self.assertSequenceEqual(books_qs, [book]) | ||||
|         # self.assertEqual(ctx[0]['sql'].count('SELECT'), 2) | ||||
|  | ||||
|     @skipUnlessDBFeature('supports_subqueries_in_group_by') | ||||
|     def test_aggregation_nested_subquery_outerref(self): | ||||
|         publisher_with_same_name = Publisher.objects.filter( | ||||
|             id__in=Subquery( | ||||
|                 Publisher.objects.filter( | ||||
|                     name=OuterRef(OuterRef('publisher__name')), | ||||
|                 ).values('id'), | ||||
|             ), | ||||
|         ).values(publisher_count=Count('id'))[:1] | ||||
|         books_breakdown = Book.objects.annotate( | ||||
|             publisher_count=Subquery(publisher_with_same_name), | ||||
|             authors_count=Count('authors'), | ||||
|         ).values_list('publisher_count', flat=True) | ||||
|         self.assertSequenceEqual(books_breakdown, [1] * 6) | ||||
|  | ||||
|     def test_aggregation_random_ordering(self): | ||||
|         """Random() is not included in the GROUP BY when used for ordering.""" | ||||
|         authors = Author.objects.annotate(contact_count=Count('book')).order_by('?') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user