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:
parent
f5ed27cf1f
commit
15b1675af9
|
@ -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>]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue