mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #23659 -- Kept annotate() args ordering
Thanks Loic Bistuer and Simon Charette for the review.
This commit is contained in:
		| @@ -2,7 +2,7 @@ | |||||||
| The main QuerySet implementation. This provides the public API for the ORM. | The main QuerySet implementation. This provides the public API for the ORM. | ||||||
| """ | """ | ||||||
|  |  | ||||||
| from collections import deque | from collections import deque, OrderedDict | ||||||
| import copy | import copy | ||||||
| import sys | import sys | ||||||
| import warnings | import warnings | ||||||
| @@ -786,27 +786,29 @@ class QuerySet(object): | |||||||
|         Return a query set in which the returned objects have been annotated |         Return a query set in which the returned objects have been annotated | ||||||
|         with data aggregated from related fields. |         with data aggregated from related fields. | ||||||
|         """ |         """ | ||||||
|  |         aggrs = OrderedDict()  # To preserve ordering of args | ||||||
|         for arg in args: |         for arg in args: | ||||||
|             if arg.default_alias in kwargs: |             if arg.default_alias in kwargs: | ||||||
|                 raise ValueError("The named annotation '%s' conflicts with the " |                 raise ValueError("The named annotation '%s' conflicts with the " | ||||||
|                                  "default name for another annotation." |                                  "default name for another annotation." | ||||||
|                                  % arg.default_alias) |                                  % arg.default_alias) | ||||||
|             kwargs[arg.default_alias] = arg |             aggrs[arg.default_alias] = arg | ||||||
|  |         aggrs.update(kwargs) | ||||||
|  |  | ||||||
|         names = getattr(self, '_fields', None) |         names = getattr(self, '_fields', None) | ||||||
|         if names is None: |         if names is None: | ||||||
|             names = set(self.model._meta.get_all_field_names()) |             names = set(self.model._meta.get_all_field_names()) | ||||||
|         for aggregate in kwargs: |         for aggregate in aggrs: | ||||||
|             if aggregate in names: |             if aggregate in names: | ||||||
|                 raise ValueError("The annotation '%s' conflicts with a field on " |                 raise ValueError("The annotation '%s' conflicts with a field on " | ||||||
|                     "the model." % aggregate) |                     "the model." % aggregate) | ||||||
|  |  | ||||||
|         obj = self._clone() |         obj = self._clone() | ||||||
|  |  | ||||||
|         obj._setup_aggregate_query(list(kwargs)) |         obj._setup_aggregate_query(list(aggrs)) | ||||||
|  |  | ||||||
|         # Add the aggregates to the query |         # Add the aggregates to the query | ||||||
|         for (alias, aggregate_expr) in kwargs.items(): |         for (alias, aggregate_expr) in aggrs.items(): | ||||||
|             obj.query.add_aggregate(aggregate_expr, self.model, alias, |             obj.query.add_aggregate(aggregate_expr, self.model, alias, | ||||||
|                 is_summary=False) |                 is_summary=False) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -740,6 +740,17 @@ class AggregationTests(TestCase): | |||||||
|             list(qs), list(Book.objects.values_list("name", flat=True)) |             list(qs), list(Book.objects.values_list("name", flat=True)) | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  |     def test_values_list_annotation_args_ordering(self): | ||||||
|  |         """ | ||||||
|  |         Annotate *args ordering should be preserved in values_list results. | ||||||
|  |         **kwargs comes after *args. | ||||||
|  |         Regression test for #23659. | ||||||
|  |         """ | ||||||
|  |         books = Book.objects.values_list("publisher__name").annotate( | ||||||
|  |             Count("id"), Avg("price"), Avg("authors__age"), avg_pgs=Avg("pages") | ||||||
|  |             ).order_by("-publisher__name") | ||||||
|  |         self.assertEqual(books[0], ('Sams', 1, 23.09, 45.0, 528.0)) | ||||||
|  |  | ||||||
|     def test_annotation_disjunction(self): |     def test_annotation_disjunction(self): | ||||||
|         qs = Book.objects.annotate(n_authors=Count("authors")).filter( |         qs = Book.objects.annotate(n_authors=Count("authors")).filter( | ||||||
|             Q(n_authors=2) | Q(name="Python Web Development with Django") |             Q(n_authors=2) | Q(name="Python Web Development with Django") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user