Fixed #21126 -- QuerySet value conversion failure
A .annotate().select_related() query resulted in misaligned rows vs columns for compiler.resolve_columns() method. Report & patch by Michael Manfre.
This commit is contained in:
parent
42b9feb2e7
commit
83554b018e
|
@ -1167,7 +1167,7 @@ class BaseDatabaseOperations(object):
|
||||||
Coerce the value returned by the database backend into a consistent type
|
Coerce the value returned by the database backend into a consistent type
|
||||||
that is compatible with the field type.
|
that is compatible with the field type.
|
||||||
"""
|
"""
|
||||||
if value is None:
|
if value is None or field is None:
|
||||||
return value
|
return value
|
||||||
internal_type = field.get_internal_type()
|
internal_type = field.get_internal_type()
|
||||||
if internal_type == 'FloatField':
|
if internal_type == 'FloatField':
|
||||||
|
|
|
@ -686,6 +686,10 @@ class SQLCompiler(object):
|
||||||
has_aggregate_select = bool(self.query.aggregate_select)
|
has_aggregate_select = bool(self.query.aggregate_select)
|
||||||
for rows in self.execute_sql(MULTI):
|
for rows in self.execute_sql(MULTI):
|
||||||
for row in rows:
|
for row in rows:
|
||||||
|
if has_aggregate_select:
|
||||||
|
loaded_fields = self.query.get_loaded_field_names().get(self.query.model, set()) or self.query.select
|
||||||
|
aggregate_start = len(self.query.extra_select) + len(loaded_fields)
|
||||||
|
aggregate_end = aggregate_start + len(self.query.aggregate_select)
|
||||||
if resolve_columns:
|
if resolve_columns:
|
||||||
if fields is None:
|
if fields is None:
|
||||||
# We only set this up here because
|
# We only set this up here because
|
||||||
|
@ -712,12 +716,14 @@ class SQLCompiler(object):
|
||||||
db_table = self.query.get_meta().db_table
|
db_table = self.query.get_meta().db_table
|
||||||
fields = [f for f in fields if db_table in only_load and
|
fields = [f for f in fields if db_table in only_load and
|
||||||
f.column in only_load[db_table]]
|
f.column in only_load[db_table]]
|
||||||
|
if has_aggregate_select:
|
||||||
|
# pad None in to fields for aggregates
|
||||||
|
fields = fields[:aggregate_start] + [
|
||||||
|
None for x in range(0, aggregate_end - aggregate_start)
|
||||||
|
] + fields[aggregate_start:]
|
||||||
row = self.resolve_columns(row, fields)
|
row = self.resolve_columns(row, fields)
|
||||||
|
|
||||||
if has_aggregate_select:
|
if has_aggregate_select:
|
||||||
loaded_fields = self.query.get_loaded_field_names().get(self.query.model, set()) or self.query.select
|
|
||||||
aggregate_start = len(self.query.extra_select) + len(loaded_fields)
|
|
||||||
aggregate_end = aggregate_start + len(self.query.aggregate_select)
|
|
||||||
row = tuple(row[:aggregate_start]) + tuple(
|
row = tuple(row[:aggregate_start]) + tuple(
|
||||||
self.query.resolve_aggregate(value, aggregate, self.connection)
|
self.query.resolve_aggregate(value, aggregate, self.connection)
|
||||||
for (alias, aggregate), value
|
for (alias, aggregate), value
|
||||||
|
|
|
@ -393,6 +393,17 @@ class AggregationTests(TestCase):
|
||||||
qs = Entries.objects.annotate(clue_count=Count('clues__ID'))
|
qs = Entries.objects.annotate(clue_count=Count('clues__ID'))
|
||||||
self.assertQuerysetEqual(qs, [])
|
self.assertQuerysetEqual(qs, [])
|
||||||
|
|
||||||
|
def test_boolean_conversion(self):
|
||||||
|
# Aggregates mixed up ordering of columns for backend's convert_values
|
||||||
|
# method. Refs #21126.
|
||||||
|
e = Entries.objects.create(Entry='foo')
|
||||||
|
c = Clues.objects.create(EntryID=e, Clue='bar')
|
||||||
|
qs = Clues.objects.select_related('EntryID').annotate(Count('ID'))
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
qs, [c], lambda x: x)
|
||||||
|
self.assertEqual(qs[0].EntryID, e)
|
||||||
|
self.assertIs(qs[0].EntryID.Exclude, False)
|
||||||
|
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
# Regression for #10089: Check handling of empty result sets with
|
# Regression for #10089: Check handling of empty result sets with
|
||||||
# aggregates
|
# aggregates
|
||||||
|
|
Loading…
Reference in New Issue