Fixed small inconsistency when handling aggregate's default_alias.

Refs #14030.
This commit is contained in:
Loic Bistuer 2015-01-21 12:47:49 +07:00
parent 039465a6a7
commit d450af8a26
2 changed files with 15 additions and 5 deletions

View File

@ -288,7 +288,13 @@ class QuerySet(object):
if self.query.distinct_fields: if self.query.distinct_fields:
raise NotImplementedError("aggregate() + distinct(fields) not implemented.") raise NotImplementedError("aggregate() + distinct(fields) not implemented.")
for arg in args: for arg in args:
if not hasattr(arg, 'default_alias'): # The default_alias property may raise a TypeError, so we use
# a try/except construct rather than hasattr in order to remain
# consistent between PY2 and PY3 (hasattr would swallow
# the TypeError on PY2).
try:
arg.default_alias
except (AttributeError, TypeError):
raise TypeError("Complex aggregates require an alias") raise TypeError("Complex aggregates require an alias")
kwargs[arg.default_alias] = arg kwargs[arg.default_alias] = arg
@ -759,14 +765,16 @@ class QuerySet(object):
""" """
annotations = OrderedDict() # To preserve ordering of args annotations = OrderedDict() # To preserve ordering of args
for arg in args: for arg in args:
# The default_alias property may raise a TypeError, so we use
# a try/except construct rather than hasattr in order to remain
# consistent between PY2 and PY3 (hasattr would swallow
# the TypeError on PY2).
try: try:
# we can't do an hasattr here because py2 returns False
# if default_alias exists but throws a TypeError
if arg.default_alias in kwargs: if arg.default_alias in kwargs:
raise ValueError("The named annotation '%s' conflicts with the " raise ValueError("The named annotation '%s' conflicts with the "
"default name for another annotation." "default name for another annotation."
% arg.default_alias) % arg.default_alias)
except AttributeError: # default_alias except (AttributeError, TypeError):
raise TypeError("Complex annotations require an alias") raise TypeError("Complex annotations require an alias")
annotations[arg.default_alias] = arg annotations[arg.default_alias] = arg
annotations.update(kwargs) annotations.update(kwargs)

View File

@ -768,10 +768,12 @@ class ComplexAggregateTestCase(TestCase):
self.assertEqual(b3.sums, Approximate(Decimal("383.69"), places=2)) self.assertEqual(b3.sums, Approximate(Decimal("383.69"), places=2))
def test_complex_aggregations_require_kwarg(self): def test_complex_aggregations_require_kwarg(self):
with six.assertRaisesRegex(self, TypeError, 'Complex expressions require an alias'): with six.assertRaisesRegex(self, TypeError, 'Complex annotations require an alias'):
Author.objects.annotate(Sum(F('age') + F('friends__age'))) Author.objects.annotate(Sum(F('age') + F('friends__age')))
with six.assertRaisesRegex(self, TypeError, 'Complex aggregates require an alias'): with six.assertRaisesRegex(self, TypeError, 'Complex aggregates require an alias'):
Author.objects.aggregate(Sum('age') / Count('age')) Author.objects.aggregate(Sum('age') / Count('age'))
with six.assertRaisesRegex(self, TypeError, 'Complex aggregates require an alias'):
Author.objects.aggregate(Sum(Value(1)))
def test_aggregate_over_complex_annotation(self): def test_aggregate_over_complex_annotation(self):
qs = Author.objects.annotate( qs = Author.objects.annotate(