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]
|
field_name = field_list[0]
|
||||||
col = field_name
|
col = field_name
|
||||||
source = self.aggregates[field_name]
|
source = self.aggregates[field_name]
|
||||||
elif (len(field_list) > 1 or
|
elif ((len(field_list) > 1) or
|
||||||
field_list[0] not in [i.name for i in opts.fields]):
|
(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, source, opts, join_list, last, _ = self.setup_joins(
|
||||||
field_list, opts, self.get_initial_alias(), False)
|
field_list, opts, self.get_initial_alias(), False)
|
||||||
|
|
||||||
|
@ -1419,15 +1428,11 @@ class BaseQuery(object):
|
||||||
|
|
||||||
col = (join_list[-1], col)
|
col = (join_list[-1], col)
|
||||||
else:
|
else:
|
||||||
# Aggregate references a normal field
|
# The simplest cases. No joins required -
|
||||||
|
# just reference the provided column alias.
|
||||||
field_name = field_list[0]
|
field_name = field_list[0]
|
||||||
source = opts.get_field(field_name)
|
source = opts.get_field(field_name)
|
||||||
if not (self.group_by is not None and is_summary):
|
col = field_name
|
||||||
# Only use a column alias if this is a
|
|
||||||
# standalone aggregate, or an annotation
|
|
||||||
col = (opts.db_table, source.column)
|
|
||||||
else:
|
|
||||||
col = field_name
|
|
||||||
|
|
||||||
# Add the aggregate to the query
|
# Add the aggregate to the query
|
||||||
alias = truncate_name(alias, self.connection.ops.max_name_length())
|
alias = truncate_name(alias, self.connection.ops.max_name_length())
|
||||||
|
@ -1659,7 +1664,6 @@ class BaseQuery(object):
|
||||||
last.append(len(joins))
|
last.append(len(joins))
|
||||||
if name == 'pk':
|
if name == 'pk':
|
||||||
name = opts.pk.name
|
name = opts.pk.name
|
||||||
|
|
||||||
try:
|
try:
|
||||||
field, model, direct, m2m = opts.get_field_by_name(name)
|
field, model, direct, m2m = opts.get_field_by_name(name)
|
||||||
except FieldDoesNotExist:
|
except FieldDoesNotExist:
|
||||||
|
|
|
@ -239,5 +239,19 @@
|
||||||
"friends": [8],
|
"friends": [8],
|
||||||
"name": "Stuart Russell"
|
"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')
|
EntryID = models.ForeignKey(Entries, verbose_name='Entry', db_column = 'Entry ID')
|
||||||
Clue = models.CharField(max_length=150)
|
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': """
|
__test__ = {'API_TESTS': """
|
||||||
>>> from django.core import management
|
>>> from django.core import management
|
||||||
>>> from django.db.models import get_app, F
|
>>> from django.db.models import get_app, F
|
||||||
|
@ -137,17 +143,17 @@ __test__ = {'API_TESTS': """
|
||||||
>>> Book.objects.all().aggregate(num_authors=Count('foo'))
|
>>> Book.objects.all().aggregate(num_authors=Count('foo'))
|
||||||
Traceback (most recent call last):
|
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'))
|
>>> Book.objects.all().annotate(num_authors=Count('foo'))
|
||||||
Traceback (most recent call last):
|
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'))
|
>>> Book.objects.all().annotate(num_authors=Count('authors__id')).aggregate(Max('foo'))
|
||||||
Traceback (most recent call last):
|
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
|
# Old-style count aggregations can be mixed with new-style
|
||||||
>>> Book.objects.annotate(num_authors=Count('authors')).count()
|
>>> Book.objects.annotate(num_authors=Count('authors')).count()
|
||||||
|
@ -276,6 +282,22 @@ FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, conta
|
||||||
|
|
||||||
>>> publishers
|
>>> publishers
|
||||||
[<Publisher: Apress>, <Publisher: Sams>]
|
[<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