Fixed #25414 -- Fixed QuerySet.annotate() with pk in values() on MySQL.
Thanks Tim Graham and Simon Charette for the reviews.
This commit is contained in:
parent
b59c0d722d
commit
1d070d027c
|
@ -135,9 +135,7 @@ class SQLCompiler:
|
||||||
# include the primary key of every table, but for MySQL it is enough to
|
# include the primary key of every table, but for MySQL it is enough to
|
||||||
# have the main table's primary key.
|
# have the main table's primary key.
|
||||||
if self.connection.features.allows_group_by_pk:
|
if self.connection.features.allows_group_by_pk:
|
||||||
# The logic here is: if the main model's primary key is in the
|
# Determine if the main model's primary key is in the query.
|
||||||
# query, then set new_expressions to that field. If that happens,
|
|
||||||
# then also add having expressions to group by.
|
|
||||||
pk = None
|
pk = None
|
||||||
for expr in expressions:
|
for expr in expressions:
|
||||||
# Is this a reference to query's base table primary key? If the
|
# Is this a reference to query's base table primary key? If the
|
||||||
|
@ -146,9 +144,18 @@ class SQLCompiler:
|
||||||
getattr(expr, 'alias', None) == self.query.tables[0]):
|
getattr(expr, 'alias', None) == self.query.tables[0]):
|
||||||
pk = expr
|
pk = expr
|
||||||
break
|
break
|
||||||
|
# If the main model's primary key is in the query, group by that
|
||||||
|
# field, HAVING expressions, and expressions associated with tables
|
||||||
|
# that don't have a primary key included in the grouped columns.
|
||||||
if pk:
|
if pk:
|
||||||
# MySQLism: Columns in HAVING clause must be added to the GROUP BY.
|
pk_aliases = {
|
||||||
expressions = [pk] + [expr for expr in expressions if expr in having]
|
expr.alias for expr in expressions
|
||||||
|
if hasattr(expr, 'target') and expr.target.primary_key
|
||||||
|
}
|
||||||
|
expressions = [pk] + [
|
||||||
|
expr for expr in expressions
|
||||||
|
if expr in having or getattr(expr, 'alias', None) not in pk_aliases
|
||||||
|
]
|
||||||
elif self.connection.features.allows_group_by_selected_pks:
|
elif self.connection.features.allows_group_by_selected_pks:
|
||||||
# Filter out all expressions associated with a table's primary key
|
# Filter out all expressions associated with a table's primary key
|
||||||
# present in the grouped columns. This is done by identifying all
|
# present in the grouped columns. This is done by identifying all
|
||||||
|
|
|
@ -297,6 +297,12 @@ class NonAggregateAnnotationTestCase(TestCase):
|
||||||
self.assertEqual(book['other_rating'], 4)
|
self.assertEqual(book['other_rating'], 4)
|
||||||
self.assertEqual(book['other_isbn'], '155860191')
|
self.assertEqual(book['other_isbn'], '155860191')
|
||||||
|
|
||||||
|
def test_values_with_pk_annotation(self):
|
||||||
|
# annotate references a field in values() with pk
|
||||||
|
publishers = Publisher.objects.values('id', 'book__rating').annotate(total=Sum('book__rating'))
|
||||||
|
for publisher in publishers.filter(pk=self.p1.pk):
|
||||||
|
self.assertEqual(publisher['book__rating'], publisher['total'])
|
||||||
|
|
||||||
def test_defer_annotation(self):
|
def test_defer_annotation(self):
|
||||||
"""
|
"""
|
||||||
Deferred attributes can be referenced by an annotation,
|
Deferred attributes can be referenced by an annotation,
|
||||||
|
|
Loading…
Reference in New Issue