diff options
Diffstat (limited to 'django/db/models/sql')
| -rw-r--r-- | django/db/models/sql/compiler.py | 9 | ||||
| -rw-r--r-- | django/db/models/sql/query.py | 42 |
2 files changed, 35 insertions, 16 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 3d434d5909..3a2e29a76f 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -109,7 +109,14 @@ class SQLCompiler: # Note that even if the group_by is set, it is only the minimal # set to group by. So, we need to add cols in select, order_by, and # having into the select in any case. + ref_sources = { + expr.source for expr in expressions if isinstance(expr, Ref) + } for expr, _, _ in select: + # Skip members of the select clause that are already included + # by reference. + if expr in ref_sources: + continue cols = expr.get_group_by_cols() for col in cols: expressions.append(col) @@ -399,7 +406,7 @@ class SQLCompiler: return self.quote_cache[name] if ((name in self.query.alias_map and name not in self.query.table_map) or name in self.query.extra_select or ( - name in self.query.external_aliases and name not in self.query.table_map)): + self.query.external_aliases.get(name) and name not in self.query.table_map)): self.quote_cache[name] = name return name r = self.connection.ops.quote_name(name) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index d002698c63..ac4822e18a 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -157,7 +157,8 @@ class Query(BaseExpression): # Sometimes the query contains references to aliases in outer queries (as # a result of split_exclude). Correct alias quoting needs to know these # aliases too. - self.external_aliases = set() + # Map external tables to whether they are aliased. + self.external_aliases = {} self.table_map = {} # Maps table names to list of aliases. self.default_cols = True self.default_ordering = True @@ -855,8 +856,11 @@ class Query(BaseExpression): if alias == old_alias: table_aliases[pos] = new_alias break - self.external_aliases = {change_map.get(alias, alias) - for alias in self.external_aliases} + self.external_aliases = { + # Table is aliased or it's being changed and thus is aliased. + change_map.get(alias, alias): (aliased or alias in change_map) + for alias, aliased in self.external_aliases.items() + } def bump_prefix(self, outer_query): """ @@ -1030,19 +1034,23 @@ class Query(BaseExpression): for key, value in clone.annotations.items(): resolved = value.resolve_expression(query, *args, **kwargs) if hasattr(resolved, 'external_aliases'): - resolved.external_aliases.update(clone.alias_map) + resolved.external_aliases.update(clone.external_aliases) clone.annotations[key] = resolved # Outer query's aliases are considered external. - clone.external_aliases.update( - alias for alias, table in query.alias_map.items() - if ( - isinstance(table, Join) and table.join_field.related_model._meta.db_table != alias - ) or ( - isinstance(table, BaseTable) and table.table_name != table.table_alias + for alias, table in query.alias_map.items(): + clone.external_aliases[alias] = ( + (isinstance(table, Join) and table.join_field.related_model._meta.db_table != alias) or + (isinstance(table, BaseTable) and table.table_name != table.table_alias) ) - ) return clone + def get_external_cols(self): + exprs = chain(self.annotations.values(), self.where.children) + return [ + col for col in self._gen_cols(exprs) + if col.alias in self.external_aliases + ] + def as_sql(self, compiler, connection): sql, params = self.get_compiler(connection=connection).as_sql() if self.subquery: @@ -1635,12 +1643,16 @@ class Query(BaseExpression): return targets, joins[-1], joins @classmethod - def _gen_col_aliases(cls, exprs): + def _gen_cols(cls, exprs): for expr in exprs: if isinstance(expr, Col): - yield expr.alias + yield expr else: - yield from cls._gen_col_aliases(expr.get_source_expressions()) + yield from cls._gen_cols(expr.get_source_expressions()) + + @classmethod + def _gen_col_aliases(cls, exprs): + yield from (expr.alias for expr in cls._gen_cols(exprs)) def resolve_ref(self, name, allow_joins=True, reuse=None, summarize=False): if not allow_joins and LOOKUP_SEP in name: @@ -1733,7 +1745,7 @@ class Query(BaseExpression): lookup = lookup_class(pk.get_col(query.select[0].alias), pk.get_col(alias)) query.where.add(lookup, AND) - query.external_aliases.add(alias) + query.external_aliases[alias] = True condition, needed_inner = self.build_filter( ('%s__in' % trimmed_prefix, query), |
