mirror of https://github.com/django/django.git
Fixed #10666 -- Corrected the handling of inherited fields with aggregate() and annotate(). Thanks to julienb for the report.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@10446 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
aa9a40b0d8
commit
98ef7e85bd
|
@ -1403,8 +1403,17 @@ class BaseQuery(object):
|
|||
field_name = field_list[0]
|
||||
col = field_name
|
||||
source = self.aggregates[field_name]
|
||||
elif (len(field_list) > 1 or
|
||||
field_list[0] not in [i.name for i in opts.fields]):
|
||||
elif ((len(field_list) > 1) or
|
||||
(field_list[0] not in [i.name for i in opts.fields]) or
|
||||
self.group_by is None or
|
||||
not is_summary):
|
||||
# If:
|
||||
# - the field descriptor has more than one part (foo__bar), or
|
||||
# - the field descriptor is referencing an m2m/m2o field, or
|
||||
# - this is a reference to a model field (possibly inherited), or
|
||||
# - this is an annotation over a model field
|
||||
# then we need to explore the joins that are required.
|
||||
|
||||
field, source, opts, join_list, last, _ = self.setup_joins(
|
||||
field_list, opts, self.get_initial_alias(), False)
|
||||
|
||||
|
@ -1419,15 +1428,11 @@ class BaseQuery(object):
|
|||
|
||||
col = (join_list[-1], col)
|
||||
else:
|
||||
# Aggregate references a normal field
|
||||
# The simplest cases. No joins required -
|
||||
# just reference the provided column alias.
|
||||
field_name = field_list[0]
|
||||
source = opts.get_field(field_name)
|
||||
if not (self.group_by is not None and is_summary):
|
||||
# Only use a column alias if this is a
|
||||
# standalone aggregate, or an annotation
|
||||
col = (opts.db_table, source.column)
|
||||
else:
|
||||
col = field_name
|
||||
col = field_name
|
||||
|
||||
# Add the aggregate to the query
|
||||
alias = truncate_name(alias, self.connection.ops.max_name_length())
|
||||
|
@ -1659,7 +1664,6 @@ class BaseQuery(object):
|
|||
last.append(len(joins))
|
||||
if name == 'pk':
|
||||
name = opts.pk.name
|
||||
|
||||
try:
|
||||
field, model, direct, m2m = opts.get_field_by_name(name)
|
||||
except FieldDoesNotExist:
|
||||
|
|
|
@ -239,5 +239,19 @@
|
|||
"friends": [8],
|
||||
"name": "Stuart Russell"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 5,
|
||||
"model": "aggregation_regress.hardbackbook",
|
||||
"fields": {
|
||||
"weight": 4.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 6,
|
||||
"model": "aggregation_regress.hardbackbook",
|
||||
"fields": {
|
||||
"weight": 3.7
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -58,6 +58,12 @@ class Clues(models.Model):
|
|||
EntryID = models.ForeignKey(Entries, verbose_name='Entry', db_column = 'Entry ID')
|
||||
Clue = models.CharField(max_length=150)
|
||||
|
||||
class HardbackBook(Book):
|
||||
weight = models.FloatField()
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s (hardback): %s" % (self.name, self.weight)
|
||||
|
||||
__test__ = {'API_TESTS': """
|
||||
>>> from django.core import management
|
||||
>>> from django.db.models import get_app, F
|
||||
|
@ -137,17 +143,17 @@ __test__ = {'API_TESTS': """
|
|||
>>> Book.objects.all().aggregate(num_authors=Count('foo'))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, contact, id, isbn, name, pages, price, pubdate, publisher, rating, store
|
||||
FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, contact, hardbackbook, id, isbn, name, pages, price, pubdate, publisher, rating, store
|
||||
|
||||
>>> Book.objects.all().annotate(num_authors=Count('foo'))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, contact, id, isbn, name, pages, price, pubdate, publisher, rating, store
|
||||
FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, contact, hardbackbook, id, isbn, name, pages, price, pubdate, publisher, rating, store
|
||||
|
||||
>>> Book.objects.all().annotate(num_authors=Count('authors__id')).aggregate(Max('foo'))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, contact, id, isbn, name, pages, price, pubdate, publisher, rating, store, num_authors
|
||||
FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, contact, hardbackbook, id, isbn, name, pages, price, pubdate, publisher, rating, store, num_authors
|
||||
|
||||
# Old-style count aggregations can be mixed with new-style
|
||||
>>> Book.objects.annotate(num_authors=Count('authors')).count()
|
||||
|
@ -276,6 +282,22 @@ FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, conta
|
|||
|
||||
>>> publishers
|
||||
[<Publisher: Apress>, <Publisher: Sams>]
|
||||
|
||||
|
||||
# Regression for 10666 - inherited fields work with annotations and aggregations
|
||||
>>> HardbackBook.objects.aggregate(n_pages=Sum('book_ptr__pages'))
|
||||
{'n_pages': 2078}
|
||||
|
||||
>>> HardbackBook.objects.aggregate(n_pages=Sum('pages'))
|
||||
{'n_pages': 2078}
|
||||
|
||||
>>> HardbackBook.objects.annotate(n_authors=Count('book_ptr__authors')).values('name','n_authors')
|
||||
[{'n_authors': 2, 'name': u'Artificial Intelligence: A Modern Approach'}, {'n_authors': 1, 'name': u'Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp'}]
|
||||
|
||||
>>> HardbackBook.objects.annotate(n_authors=Count('authors')).values('name','n_authors')
|
||||
[{'n_authors': 2, 'name': u'Artificial Intelligence: A Modern Approach'}, {'n_authors': 1, 'name': u'Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp'}]
|
||||
|
||||
|
||||
"""
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue