mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #10113 -- Ensured that joined fields mentioned in order_by() are included in the GROUP_BY clause on those backends that require it. Thanks to Koen Biermans <koen.biermans@werk.belgie.be> for the report.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@9788 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -346,7 +346,7 @@ class BaseQuery(object): | |||||||
|         """ |         """ | ||||||
|         self.pre_sql_setup() |         self.pre_sql_setup() | ||||||
|         out_cols = self.get_columns(with_col_aliases) |         out_cols = self.get_columns(with_col_aliases) | ||||||
|         ordering = self.get_ordering() |         ordering, ordering_group_by = self.get_ordering() | ||||||
|  |  | ||||||
|         # This must come after 'select' and 'ordering' -- see docstring of |         # This must come after 'select' and 'ordering' -- see docstring of | ||||||
|         # get_from_clause() for details. |         # get_from_clause() for details. | ||||||
| @@ -380,9 +380,15 @@ class BaseQuery(object): | |||||||
|  |  | ||||||
|         if self.group_by: |         if self.group_by: | ||||||
|             grouping = self.get_grouping() |             grouping = self.get_grouping() | ||||||
|             result.append('GROUP BY %s' % ', '.join(grouping)) |             if ordering: | ||||||
|             if not ordering: |                 # If the backend can't group by PK (i.e., any database | ||||||
|  |                 # other than MySQL), then any fields mentioned in the | ||||||
|  |                 # ordering clause needs to be in the group by clause. | ||||||
|  |                 if not self.connection.features.allows_group_by_pk: | ||||||
|  |                     grouping.extend(ordering_group_by) | ||||||
|  |             else: | ||||||
|                 ordering = self.connection.ops.force_no_ordering() |                 ordering = self.connection.ops.force_no_ordering() | ||||||
|  |             result.append('GROUP BY %s' % ', '.join(grouping)) | ||||||
|  |  | ||||||
|         if having: |         if having: | ||||||
|             result.append('HAVING %s' % having) |             result.append('HAVING %s' % having) | ||||||
| @@ -701,7 +707,10 @@ class BaseQuery(object): | |||||||
|  |  | ||||||
|     def get_ordering(self): |     def get_ordering(self): | ||||||
|         """ |         """ | ||||||
|         Returns list representing the SQL elements in the "order by" clause. |         Returns a tuple containing a list representing the SQL elements in the | ||||||
|  |         "order by" clause, and the list of SQL elements that need to be added | ||||||
|  |         to the GROUP BY clause as a result of the ordering. | ||||||
|  |  | ||||||
|         Also sets the ordering_aliases attribute on this instance to a list of |         Also sets the ordering_aliases attribute on this instance to a list of | ||||||
|         extra aliases needed in the select. |         extra aliases needed in the select. | ||||||
|  |  | ||||||
| @@ -719,6 +728,7 @@ class BaseQuery(object): | |||||||
|         distinct = self.distinct |         distinct = self.distinct | ||||||
|         select_aliases = self._select_aliases |         select_aliases = self._select_aliases | ||||||
|         result = [] |         result = [] | ||||||
|  |         group_by = [] | ||||||
|         ordering_aliases = [] |         ordering_aliases = [] | ||||||
|         if self.standard_ordering: |         if self.standard_ordering: | ||||||
|             asc, desc = ORDER_DIR['ASC'] |             asc, desc = ORDER_DIR['ASC'] | ||||||
| @@ -741,6 +751,7 @@ class BaseQuery(object): | |||||||
|                 else: |                 else: | ||||||
|                     order = asc |                     order = asc | ||||||
|                 result.append('%s %s' % (field, order)) |                 result.append('%s %s' % (field, order)) | ||||||
|  |                 group_by.append(field) | ||||||
|                 continue |                 continue | ||||||
|             col, order = get_order_dir(field, asc) |             col, order = get_order_dir(field, asc) | ||||||
|             if col in self.aggregate_select: |             if col in self.aggregate_select: | ||||||
| @@ -755,6 +766,7 @@ class BaseQuery(object): | |||||||
|                     processed_pairs.add((table, col)) |                     processed_pairs.add((table, col)) | ||||||
|                     if not distinct or elt in select_aliases: |                     if not distinct or elt in select_aliases: | ||||||
|                         result.append('%s %s' % (elt, order)) |                         result.append('%s %s' % (elt, order)) | ||||||
|  |                         group_by.append(elt) | ||||||
|             elif get_order_dir(field)[0] not in self.extra_select: |             elif get_order_dir(field)[0] not in self.extra_select: | ||||||
|                 # 'col' is of the form 'field' or 'field1__field2' or |                 # 'col' is of the form 'field' or 'field1__field2' or | ||||||
|                 # '-field1__field2__field', etc. |                 # '-field1__field2__field', etc. | ||||||
| @@ -766,13 +778,15 @@ class BaseQuery(object): | |||||||
|                         if distinct and elt not in select_aliases: |                         if distinct and elt not in select_aliases: | ||||||
|                             ordering_aliases.append(elt) |                             ordering_aliases.append(elt) | ||||||
|                         result.append('%s %s' % (elt, order)) |                         result.append('%s %s' % (elt, order)) | ||||||
|  |                         group_by.append(elt) | ||||||
|             else: |             else: | ||||||
|                 elt = qn2(col) |                 elt = qn2(col) | ||||||
|                 if distinct and col not in select_aliases: |                 if distinct and col not in select_aliases: | ||||||
|                     ordering_aliases.append(elt) |                     ordering_aliases.append(elt) | ||||||
|                 result.append('%s %s' % (elt, order)) |                 result.append('%s %s' % (elt, order)) | ||||||
|  |                 group_by.append(elt) | ||||||
|         self.ordering_aliases = ordering_aliases |         self.ordering_aliases = ordering_aliases | ||||||
|         return result |         return result, group_by | ||||||
|  |  | ||||||
|     def find_ordering_name(self, name, opts, alias=None, default_order='ASC', |     def find_ordering_name(self, name, opts, alias=None, default_order='ASC', | ||||||
|             already_seen=None): |             already_seen=None): | ||||||
|   | |||||||
| @@ -174,6 +174,11 @@ FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, id, i | |||||||
| >>> Publisher.objects.filter(pk=5).annotate(num_authors=Count('book__authors'), avg_authors=Avg('book__authors'), max_authors=Max('book__authors'), max_price=Max('book__price'), max_rating=Max('book__rating')).values() | >>> Publisher.objects.filter(pk=5).annotate(num_authors=Count('book__authors'), avg_authors=Avg('book__authors'), max_authors=Max('book__authors'), max_price=Max('book__price'), max_rating=Max('book__rating')).values() | ||||||
| [{'max_authors': None, 'name': u"Jonno's House of Books", 'num_awards': 0, 'max_price': None, 'num_authors': 0, 'max_rating': None, 'id': 5, 'avg_authors': None}] | [{'max_authors': None, 'name': u"Jonno's House of Books", 'num_awards': 0, 'max_price': None, 'num_authors': 0, 'max_rating': None, 'id': 5, 'avg_authors': None}] | ||||||
|  |  | ||||||
|  | # Regression for #10113 - Fields mentioned in order_by() must be included in the GROUP BY. | ||||||
|  | # This only becomes a problem when the order_by introduces a new join. | ||||||
|  | >>> Book.objects.annotate(num_authors=Count('authors')).order_by('publisher__name') | ||||||
|  | [<Book: The Definitive Guide to Django: Web Development Done Right>, <Book: Practical Django Projects>, <Book: Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp>, <Book: Python Web Development with Django>, <Book: Artificial Intelligence: A Modern Approach>, <Book: Sams Teach Yourself Django in 24 Hours>] | ||||||
|  |  | ||||||
| """ | """ | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user