Fixed #11881 -- removed junk from aggregation subqueries

There were clauses that weren't needed in the subqueries. These were
ORDER BY, SELECT FOR UPDATE and related selections.
This commit is contained in:
Anssi Kääriäinen 2013-08-19 16:14:31 +03:00
parent 7737305a4f
commit 7bc57a6d71
2 changed files with 26 additions and 1 deletions

View File

@ -330,8 +330,16 @@ class Query(object):
from django.db.models.sql.subqueries import AggregateQuery
query = AggregateQuery(self.model)
obj = self.clone()
relabels = dict((t, 'subquery') for t in self.tables)
if not force_subq:
# In forced subq case the ordering and limits will likely
# affect the results.
obj.clear_ordering(True)
obj.clear_limits()
obj.select_for_update = False
obj.select_related = False
obj.related_select_cols = []
relabels = dict((t, 'subquery') for t in self.tables)
# Remove any aggregates marked for reduction from the subquery
# and move them to the outer AggregateQuery.
for alias, aggregate in self.aggregate_select.items():

View File

@ -3,8 +3,10 @@ from __future__ import unicode_literals
import datetime
from decimal import Decimal
from django.db import connection
from django.db.models import Avg, Sum, Count, Max, Min
from django.test import TestCase, Approximate
from django.test.utils import CaptureQueriesContext
from .models import Author, Publisher, Book, Store
@ -625,3 +627,18 @@ class BaseAggregateTestCase(TestCase):
qs = Book.objects.all().order_by('-rating')[0:3]
vals = qs.aggregate(average_top3_rating=Avg('rating'))['average_top3_rating']
self.assertAlmostEqual(vals, 4.5, places=2)
def test_ticket11881(self):
"""
Check that subqueries do not needlessly contain ORDER BY, SELECT FOR UPDATE
or select_related() stuff.
"""
qs = Book.objects.all().select_for_update().order_by(
'pk').select_related('publisher').annotate(max_pk=Max('pk'))
with CaptureQueriesContext(connection) as captured_queries:
qs.aggregate(avg_pk=Avg('max_pk'))
self.assertEqual(len(captured_queries), 1)
qstr = captured_queries[0]['sql'].lower()
self.assertNotIn('for update', qstr)
self.assertNotIn('order by', qstr)
self.assertEqual(qstr.count(' join '), 0)