Fixed small inconsistency when handling aggregate's default_alias.
Refs #14030.
This commit is contained in:
parent
039465a6a7
commit
d450af8a26
|
@ -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)
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue