Commit 4276b519 authored by Alex Gaynor's avatar Alex Gaynor
Browse files

Fixed #12687 -- fixed an issue with aggregates and counts in conjunction with...

Fixed #12687 -- fixed an issue with aggregates and counts in conjunction with annotations where the QuerySet was provably empty.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14586 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 3e9d2f81
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ class AggregateField(object):
    """
    def __init__(self, internal_type):
        self.internal_type = internal_type

    def get_internal_type(self):
        return self.internal_type

+16 −4
Original line number Diff line number Diff line
@@ -337,7 +337,7 @@ class Query(object):
        # information but retrieves only the first row. Aggregate
        # over the subquery instead.
        if self.group_by is not None:
            from subqueries import AggregateQuery
            from django.db.models.sql.subqueries import AggregateQuery
            query = AggregateQuery(self.model)

            obj = self.clone()
@@ -349,7 +349,13 @@ class Query(object):
                    query.aggregate_select[alias] = aggregate
                    del obj.aggregate_select[alias]

            try:
                query.add_subquery(obj, using)
            except EmptyResultSet:
                return dict(
                    (alias, None)
                    for alias in query.aggregate_select
                )
        else:
            query = self
            self.select = []
@@ -382,13 +388,19 @@ class Query(object):
            # If a select clause exists, then the query has already started to
            # specify the columns that are to be returned.
            # In this case, we need to use a subquery to evaluate the count.
            from subqueries import AggregateQuery
            from django.db.models.sql.subqueries import AggregateQuery
            subquery = obj
            subquery.clear_ordering(True)
            subquery.clear_limits()

            obj = AggregateQuery(obj.model)
            try:
                obj.add_subquery(subquery, using=using)
            except EmptyResultSet:
                # add_subquery evaluates the query, if it's an EmptyResultSet
                # then there are can be no results, and therefore there the
                # count is obviously 0
                return 0

        obj.add_count_column()
        number = obj.get_aggregation(using=using)[None]
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ from django.db.models.sql.expressions import SQLEvaluator
from django.db.models.sql.query import Query
from django.db.models.sql.where import AND, Constraint


__all__ = ['DeleteQuery', 'UpdateQuery', 'InsertQuery', 'DateQuery',
        'AggregateQuery']

+18 −0
Original line number Diff line number Diff line
@@ -622,6 +622,24 @@ class AggregationTests(TestCase):
            lambda: Book.objects.annotate(mean_age=Avg('authors__age')).annotate(Avg('mean_age'))
        )

    def test_empty_filter_count(self):
        self.assertEqual(
            Author.objects.filter(id__in=[]).annotate(Count("friends")).count(),
            0
        )

    def test_empty_filter_aggregate(self):
        self.assertEqual(
            Author.objects.filter(id__in=[]).annotate(Count("friends")).aggregate(Count("pk")),
            {"pk__count": None}
        )

    def test_annotate_and_join(self):
        self.assertEqual(
            Author.objects.annotate(c=Count("friends__name")).exclude(friends__name="Joe").count(),
            Author.objects.count()
        )

    @skipUnlessDBFeature('supports_stddev')
    def test_stddev(self):
        self.assertEqual(