Removed obsolete Query.tables attribute.

Obsolete since Query.alias_map became an OrderedDict (refs #26522).
This commit is contained in:
Anssi Kääriäinen 2017-06-28 06:23:37 +00:00 committed by Tim Graham
parent 550cb3a365
commit f7f5edd50d
5 changed files with 29 additions and 26 deletions

View File

@ -971,7 +971,7 @@ class Subquery(Expression):
clone.queryset.query = clone.queryset.query.relabeled_clone(change_map) clone.queryset.query = clone.queryset.query.relabeled_clone(change_map)
clone.queryset.query.external_aliases.update( clone.queryset.query.external_aliases.update(
alias for alias in change_map.values() alias for alias in change_map.values()
if alias not in clone.queryset.query.tables if alias not in clone.queryset.query.alias_map
) )
return clone return clone

View File

@ -31,7 +31,7 @@ class SQLCompiler:
self.ordering_parts = re.compile(r'(.*)\s(ASC|DESC)(.*)') self.ordering_parts = re.compile(r'(.*)\s(ASC|DESC)(.*)')
def setup_query(self): def setup_query(self):
if all(self.query.alias_refcount[a] == 0 for a in self.query.tables): if all(self.query.alias_refcount[a] == 0 for a in self.query.alias_map):
self.query.get_initial_alias() self.query.get_initial_alias()
self.select, self.klass_info, self.annotation_col_map = self.get_select() self.select, self.klass_info, self.annotation_col_map = self.get_select()
self.col_count = len(self.select) self.col_count = len(self.select)
@ -141,7 +141,7 @@ class SQLCompiler:
# Is this a reference to query's base table primary key? If the # Is this a reference to query's base table primary key? If the
# expression isn't a Col-like, then skip the expression. # expression isn't a Col-like, then skip the expression.
if (getattr(expr, 'target', None) == self.query.model._meta.pk and if (getattr(expr, 'target', None) == self.query.model._meta.pk and
getattr(expr, 'alias', None) == self.query.tables[0]): getattr(expr, 'alias', None) == self.query.base_table):
pk = expr pk = expr
break break
# If the main model's primary key is in the query, group by that # If the main model's primary key is in the query, group by that
@ -681,7 +681,7 @@ class SQLCompiler:
""" """
result = [] result = []
params = [] params = []
for alias in self.query.tables: for alias in self.query.alias_map:
if not self.query.alias_refcount[alias]: if not self.query.alias_refcount[alias]:
continue continue
try: try:
@ -1149,10 +1149,10 @@ class SQLDeleteCompiler(SQLCompiler):
Create the SQL for this query. Return the SQL string and list of Create the SQL for this query. Return the SQL string and list of
parameters. parameters.
""" """
assert len([t for t in self.query.tables if self.query.alias_refcount[t] > 0]) == 1, \ assert len([t for t in self.query.alias_map if self.query.alias_refcount[t] > 0]) == 1, \
"Can only delete from one table at a time." "Can only delete from one table at a time."
qn = self.quote_name_unless_alias qn = self.quote_name_unless_alias
result = ['DELETE FROM %s' % qn(self.query.tables[0])] result = ['DELETE FROM %s' % qn(self.query.base_table)]
where, params = self.compile(self.query.where) where, params = self.compile(self.query.where)
if where: if where:
result.append('WHERE %s' % where) result.append('WHERE %s' % where)
@ -1205,7 +1205,7 @@ class SQLUpdateCompiler(SQLCompiler):
update_params.append(val) update_params.append(val)
else: else:
values.append('%s = NULL' % qn(name)) values.append('%s = NULL' % qn(name))
table = self.query.tables[0] table = self.query.base_table
result = [ result = [
'UPDATE %s SET' % qn(table), 'UPDATE %s SET' % qn(table),
', '.join(values), ', '.join(values),

View File

@ -30,6 +30,7 @@ from django.db.models.sql.where import (
AND, OR, ExtraWhere, NothingNode, WhereNode, AND, OR, ExtraWhere, NothingNode, WhereNode,
) )
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.functional import cached_property
from django.utils.tree import Node from django.utils.tree import Node
__all__ = ['Query', 'RawQuery'] __all__ = ['Query', 'RawQuery']
@ -144,7 +145,6 @@ class Query:
# clause to contain other than default fields (values(), subqueries...) # clause to contain other than default fields (values(), subqueries...)
# Note that annotations go to annotations dictionary. # Note that annotations go to annotations dictionary.
self.select = () self.select = ()
self.tables = () # Aliases in the order they are created.
self.where = where() self.where = where()
self.where_class = where self.where_class = where
# The group_by attribute can have one of the following forms: # The group_by attribute can have one of the following forms:
@ -217,6 +217,10 @@ class Query:
def has_select_fields(self): def has_select_fields(self):
return bool(self.select or self.annotation_select_mask or self.extra_select_mask) return bool(self.select or self.annotation_select_mask or self.extra_select_mask)
@cached_property
def base_table(self):
return list(self.alias_map)[0] if self.alias_map else None
def __str__(self): def __str__(self):
""" """
Return the query as a string of SQL with the parameter values Return the query as a string of SQL with the parameter values
@ -274,7 +278,6 @@ class Query:
obj.default_ordering = self.default_ordering obj.default_ordering = self.default_ordering
obj.standard_ordering = self.standard_ordering obj.standard_ordering = self.standard_ordering
obj.select = self.select obj.select = self.select
obj.tables = self.tables
obj.where = self.where.clone() obj.where = self.where.clone()
obj.where_class = self.where_class obj.where_class = self.where_class
obj.group_by = self.group_by obj.group_by = self.group_by
@ -431,7 +434,7 @@ class Query:
inner_query.group_by = (self.model._meta.pk.get_col(inner_query.get_initial_alias()),) inner_query.group_by = (self.model._meta.pk.get_col(inner_query.get_initial_alias()),)
inner_query.default_cols = False inner_query.default_cols = False
relabels = {t: 'subquery' for t in inner_query.tables} relabels = {t: 'subquery' for t in inner_query.alias_map}
relabels[None] = 'subquery' relabels[None] = 'subquery'
# Remove any aggregates marked for reduction from the subquery # Remove any aggregates marked for reduction from the subquery
# and move them to the outer AggregateQuery. # and move them to the outer AggregateQuery.
@ -539,7 +542,7 @@ class Query:
# Note that we will be creating duplicate joins for non-m2m joins in # Note that we will be creating duplicate joins for non-m2m joins in
# the AND case. The results will be correct but this creates too many # the AND case. The results will be correct but this creates too many
# joins. This is something that could be fixed later on. # joins. This is something that could be fixed later on.
reuse = set() if conjunction else set(self.tables) reuse = set() if conjunction else set(self.alias_map)
# Base table must be present in the query - this is the same # Base table must be present in the query - this is the same
# table on both sides. # table on both sides.
self.get_initial_alias() self.get_initial_alias()
@ -549,7 +552,8 @@ class Query:
rhs_votes = set() rhs_votes = set()
# Now, add the joins from rhs query into the new query (skipping base # Now, add the joins from rhs query into the new query (skipping base
# table). # table).
for alias in rhs.tables[1:]: rhs_tables = list(rhs.alias_map)[1:]
for alias in rhs_tables:
join = rhs.alias_map[alias] join = rhs.alias_map[alias]
# If the left side of the join was already relabeled, use the # If the left side of the join was already relabeled, use the
# updated alias. # updated alias.
@ -714,7 +718,6 @@ class Query:
alias = table_name alias = table_name
self.table_map[alias] = [alias] self.table_map[alias] = [alias]
self.alias_refcount[alias] = 1 self.alias_refcount[alias] = 1
self.tables += (alias,)
return alias, True return alias, True
def ref_alias(self, alias): def ref_alias(self, alias):
@ -864,12 +867,9 @@ class Query:
self.subq_aliases = self.subq_aliases.union([self.alias_prefix]) self.subq_aliases = self.subq_aliases.union([self.alias_prefix])
outer_query.subq_aliases = outer_query.subq_aliases.union(self.subq_aliases) outer_query.subq_aliases = outer_query.subq_aliases.union(self.subq_aliases)
change_map = OrderedDict() change_map = OrderedDict()
tables = list(self.tables) for pos, alias in enumerate(self.alias_map):
for pos, alias in enumerate(tables):
new_alias = '%s%d' % (self.alias_prefix, pos) new_alias = '%s%d' % (self.alias_prefix, pos)
change_map[alias] = new_alias change_map[alias] = new_alias
tables[pos] = new_alias
self.tables = tuple(tables)
self.change_aliases(change_map) self.change_aliases(change_map)
def get_initial_alias(self): def get_initial_alias(self):
@ -877,8 +877,8 @@ class Query:
Return the first alias for this query, after increasing its reference Return the first alias for this query, after increasing its reference
count. count.
""" """
if self.tables: if self.alias_map:
alias = self.tables[0] alias = self.base_table
self.ref_alias(alias) self.ref_alias(alias)
else: else:
alias = self.join(BaseTable(self.get_meta().db_table, None)) alias = self.join(BaseTable(self.get_meta().db_table, None))
@ -1910,7 +1910,10 @@ class Query:
# Trim and operate only on tables that were generated for # Trim and operate only on tables that were generated for
# the lookup part of the query. That is, avoid trimming # the lookup part of the query. That is, avoid trimming
# joins generated for F() expressions. # joins generated for F() expressions.
lookup_tables = [t for t in self.tables if t in self._lookup_joins or t == self.tables[0]] lookup_tables = [
t for t in self.alias_map
if t in self._lookup_joins or t == self.base_table
]
for trimmed_paths, path in enumerate(all_paths): for trimmed_paths, path in enumerate(all_paths):
if path.m2m: if path.m2m:
break break
@ -1950,7 +1953,7 @@ class Query:
select_alias = lookup_tables[trimmed_paths] select_alias = lookup_tables[trimmed_paths]
# The found starting point is likely a Join instead of a BaseTable reference. # The found starting point is likely a Join instead of a BaseTable reference.
# But the first entry in the query's FROM clause must not be a JOIN. # But the first entry in the query's FROM clause must not be a JOIN.
for table in self.tables: for table in self.alias_map:
if self.alias_refcount[table] > 0: if self.alias_refcount[table] > 0:
self.alias_map[table] = BaseTable(self.alias_map[table].table_name, table) self.alias_map[table] = BaseTable(self.alias_map[table].table_name, table)
break break

View File

@ -19,7 +19,7 @@ class DeleteQuery(Query):
compiler = 'SQLDeleteCompiler' compiler = 'SQLDeleteCompiler'
def do_query(self, table, where, using): def do_query(self, table, where, using):
self.tables = (table,) self.alias_map = {table: self.alias_map[table]}
self.where = where self.where = where
cursor = self.get_compiler(using).execute_sql(CURSOR) cursor = self.get_compiler(using).execute_sql(CURSOR)
return cursor.rowcount if cursor else 0 return cursor.rowcount if cursor else 0
@ -52,8 +52,8 @@ class DeleteQuery(Query):
innerq.get_initial_alias() innerq.get_initial_alias()
# The same for our new query. # The same for our new query.
self.get_initial_alias() self.get_initial_alias()
innerq_used_tables = tuple([t for t in innerq.tables if innerq.alias_refcount[t]]) innerq_used_tables = tuple([t for t in innerq.alias_map if innerq.alias_refcount[t]])
if not innerq_used_tables or innerq_used_tables == self.tables: if not innerq_used_tables or innerq_used_tables == tuple(self.alias_map):
# There is only the base table in use in the query. # There is only the base table in use in the query.
self.where = innerq.where self.where = innerq.where
else: else:

View File

@ -272,7 +272,7 @@ class Queries1Tests(TestCase):
list(q2) list(q2)
combined_query = (q1 & q2).order_by('name').query combined_query = (q1 & q2).order_by('name').query
self.assertEqual(len([ self.assertEqual(len([
t for t in combined_query.tables if combined_query.alias_refcount[t] t for t in combined_query.alias_map if combined_query.alias_refcount[t]
]), 1) ]), 1)
def test_order_by_join_unref(self): def test_order_by_join_unref(self):
@ -499,7 +499,7 @@ class Queries1Tests(TestCase):
qs, qs,
['<Item: four>', '<Item: one>', '<Item: three>', '<Item: two>'] ['<Item: four>', '<Item: one>', '<Item: three>', '<Item: two>']
) )
self.assertEqual(len(qs.query.tables), 1) self.assertEqual(len(qs.query.alias_map), 1)
def test_tickets_2874_3002(self): def test_tickets_2874_3002(self):
qs = Item.objects.select_related().order_by('note__note', 'name') qs = Item.objects.select_related().order_by('note__note', 'name')