Commit be12f9e2 authored by Russell Keith-Magee's avatar Russell Keith-Magee
Browse files

[1.2.X] Fixed #14707 -- Relax the protections on aggregate naming collisions...

[1.2.X] Fixed #14707 -- Relax the protections on aggregate naming collisions when a ValuesQuerySet removes the colliding name. Thanks to Andy McKay for the report.

Backport of r15223 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@15224 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 73b36117
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -631,18 +631,19 @@ class QuerySet(object):
        """
        for arg in args:
            if arg.default_alias in kwargs:
                raise ValueError("The %s named annotation conflicts with the "
                raise ValueError("The named annotation '%s' conflicts with the "
                                 "default name for another annotation."
                                 % arg.default_alias)
            kwargs[arg.default_alias] = arg

        names = getattr(self, '_fields', None)
        if names is None:
            names = set(self.model._meta.get_all_field_names())
        for aggregate in kwargs:
            if aggregate in names:
                raise ValueError("The %s annotation conflicts with a field on "
                raise ValueError("The annotation '%s' conflicts with a field on "
                    "the model." % aggregate)


        obj = self._clone()

        obj._setup_aggregate_query(kwargs.keys())
+22 −0
Original line number Diff line number Diff line
@@ -495,6 +495,28 @@ class AggregationTests(TestCase):
        # Regression for #11256 - providing an aggregate name that conflicts with an m2m name on the model raises ValueError
        self.assertRaises(ValueError, Author.objects.annotate, friends=Count('friends'))

    def test_values_queryset_non_conflict(self):
        # Regression for #14707 -- If you're using a values query set, some potential conflicts are avoided.

        # age is a field on Author, so it shouldn't be allowed as an aggregate.
        # But age isn't included in the ValuesQuerySet, so it is.
        results = Author.objects.values('name').annotate(age=Count('book_contact_set'))
        self.assertEquals(len(results), 9)
        self.assertEquals(results[0]['name'], u'Adrian Holovaty')
        self.assertEquals(results[0]['age'], 1)

        # Same problem, but aggregating over m2m fields
        results = Author.objects.values('name').annotate(age=Avg('friends__age'))
        self.assertEquals(len(results), 9)
        self.assertEquals(results[0]['name'], u'Adrian Holovaty')
        self.assertEquals(results[0]['age'], 32.0)

        # Same problem, but colliding with an m2m field
        results = Author.objects.values('name').annotate(friends=Count('friends'))
        self.assertEquals(len(results), 9)
        self.assertEquals(results[0]['name'], u'Adrian Holovaty')
        self.assertEquals(results[0]['friends'], 2)

    def test_reverse_relation_name_conflict(self):
        # Regression for #11256 - providing an aggregate name that conflicts with a reverse-related name on the model raises ValueError
        self.assertRaises(ValueError, Author.objects.annotate, book_contact_set=Avg('friends__age'))