Removed obsolete Query.tables attribute.
Obsolete since Query.alias_map became an OrderedDict (refs #26522).
This commit is contained in:
parent
550cb3a365
commit
f7f5edd50d
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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')
|
||||||
|
|
Loading…
Reference in New Issue