Added Query.join_parent_model()
This simplifies especially compiler.py a lot, where almost the same code was repeated multiple times. Refs #19385
This commit is contained in:
parent
4511aeb6b8
commit
68985db482
|
@ -261,27 +261,14 @@ class SQLCompiler(object):
|
||||||
qn2 = self.connection.ops.quote_name
|
qn2 = self.connection.ops.quote_name
|
||||||
aliases = set()
|
aliases = set()
|
||||||
only_load = self.deferred_to_columns()
|
only_load = self.deferred_to_columns()
|
||||||
|
seen = self.query.included_inherited_models.copy()
|
||||||
if start_alias:
|
if start_alias:
|
||||||
seen = {None: start_alias}
|
seen[None] = start_alias
|
||||||
for field, model in opts.get_fields_with_model():
|
for field, model in opts.get_fields_with_model():
|
||||||
if from_parent and model is not None and issubclass(from_parent, model):
|
if from_parent and model is not None and issubclass(from_parent, model):
|
||||||
# Avoid loading data for already loaded parents.
|
# Avoid loading data for already loaded parents.
|
||||||
continue
|
continue
|
||||||
if start_alias:
|
alias = self.query.join_parent_model(opts, model, start_alias, seen)
|
||||||
try:
|
|
||||||
alias = seen[model]
|
|
||||||
except KeyError:
|
|
||||||
link_field = opts.get_ancestor_link(model)
|
|
||||||
alias = self.query.join((start_alias, model._meta.db_table,
|
|
||||||
link_field.column, model._meta.pk.column),
|
|
||||||
join_field=link_field)
|
|
||||||
seen[model] = alias
|
|
||||||
else:
|
|
||||||
# If we're starting from the base model of the queryset, the
|
|
||||||
# aliases will have already been set up in pre_sql_setup(), so
|
|
||||||
# we can save time here.
|
|
||||||
alias = self.query.included_inherited_models[model]
|
|
||||||
table = self.query.alias_map[alias].table_name
|
table = self.query.alias_map[alias].table_name
|
||||||
if table in only_load and field.column not in only_load[table]:
|
if table in only_load and field.column not in only_load[table]:
|
||||||
continue
|
continue
|
||||||
|
@ -623,26 +610,7 @@ class SQLCompiler(object):
|
||||||
continue
|
continue
|
||||||
table = f.rel.to._meta.db_table
|
table = f.rel.to._meta.db_table
|
||||||
promote = nullable or f.null
|
promote = nullable or f.null
|
||||||
if model:
|
alias = self.query.join_parent_model(opts, model, root_alias, {})
|
||||||
int_opts = opts
|
|
||||||
alias = root_alias
|
|
||||||
alias_chain = []
|
|
||||||
for int_model in opts.get_base_chain(model):
|
|
||||||
# Proxy model have elements in base chain
|
|
||||||
# with no parents, assign the new options
|
|
||||||
# object and skip to the next base in that
|
|
||||||
# case
|
|
||||||
if not int_opts.parents[int_model]:
|
|
||||||
int_opts = int_model._meta
|
|
||||||
continue
|
|
||||||
lhs_col = int_opts.parents[int_model].column
|
|
||||||
link_field = int_opts.get_ancestor_link(int_model)
|
|
||||||
int_opts = int_model._meta
|
|
||||||
alias = self.query.join((alias, int_opts.db_table, lhs_col,
|
|
||||||
int_opts.pk.column), promote=promote, join_field=link_field)
|
|
||||||
alias_chain.append(alias)
|
|
||||||
else:
|
|
||||||
alias = root_alias
|
|
||||||
|
|
||||||
alias = self.query.join((alias, table, f.column,
|
alias = self.query.join((alias, table, f.column,
|
||||||
f.rel.get_related_field().column),
|
f.rel.get_related_field().column),
|
||||||
|
@ -670,28 +638,8 @@ class SQLCompiler(object):
|
||||||
only_load.get(model), reverse=True):
|
only_load.get(model), reverse=True):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
alias = self.query.join_parent_model(opts, f.rel.to, root_alias, {})
|
||||||
table = model._meta.db_table
|
table = model._meta.db_table
|
||||||
int_opts = opts
|
|
||||||
alias = root_alias
|
|
||||||
alias_chain = []
|
|
||||||
chain = opts.get_base_chain(f.rel.to)
|
|
||||||
if chain is not None:
|
|
||||||
for int_model in chain:
|
|
||||||
# Proxy model have elements in base chain
|
|
||||||
# with no parents, assign the new options
|
|
||||||
# object and skip to the next base in that
|
|
||||||
# case
|
|
||||||
if not int_opts.parents[int_model]:
|
|
||||||
int_opts = int_model._meta
|
|
||||||
continue
|
|
||||||
lhs_col = int_opts.parents[int_model].column
|
|
||||||
link_field = int_opts.get_ancestor_link(int_model)
|
|
||||||
int_opts = int_model._meta
|
|
||||||
alias = self.query.join(
|
|
||||||
(alias, int_opts.db_table, lhs_col, int_opts.pk.column),
|
|
||||||
promote=True, join_field=link_field
|
|
||||||
)
|
|
||||||
alias_chain.append(alias)
|
|
||||||
alias = self.query.join(
|
alias = self.query.join(
|
||||||
(alias, table, f.rel.get_related_field().column, f.column),
|
(alias, table, f.rel.get_related_field().column, f.column),
|
||||||
promote=True, join_field=f
|
promote=True, join_field=f
|
||||||
|
|
|
@ -1004,12 +1004,40 @@ class Query(object):
|
||||||
|
|
||||||
for field, model in opts.get_fields_with_model():
|
for field, model in opts.get_fields_with_model():
|
||||||
if model not in seen:
|
if model not in seen:
|
||||||
link_field = opts.get_ancestor_link(model)
|
self.join_parent_model(opts, model, root_alias, seen)
|
||||||
seen[model] = self.join(
|
|
||||||
(root_alias, model._meta.db_table, link_field.column,
|
|
||||||
model._meta.pk.column), join_field=link_field)
|
|
||||||
self.included_inherited_models = seen
|
self.included_inherited_models = seen
|
||||||
|
|
||||||
|
def join_parent_model(self, opts, model, alias, seen):
|
||||||
|
"""
|
||||||
|
Makes sure the given 'model' is joined in the query. If 'model' isn't
|
||||||
|
a parent of 'opts' or if it is None this method is a no-op.
|
||||||
|
|
||||||
|
The 'alias' is the root alias for starting the join, 'seen' is a dict
|
||||||
|
of model -> alias of existing joins.
|
||||||
|
"""
|
||||||
|
if model in seen:
|
||||||
|
return seen[model]
|
||||||
|
int_opts = opts
|
||||||
|
chain = opts.get_base_chain(model)
|
||||||
|
if chain is None:
|
||||||
|
return alias
|
||||||
|
for int_model in chain:
|
||||||
|
if int_model in seen:
|
||||||
|
return seen[int_model]
|
||||||
|
# Proxy model have elements in base chain
|
||||||
|
# with no parents, assign the new options
|
||||||
|
# object and skip to the next base in that
|
||||||
|
# case
|
||||||
|
if not int_opts.parents[int_model]:
|
||||||
|
int_opts = int_model._meta
|
||||||
|
continue
|
||||||
|
link_field = int_opts.get_ancestor_link(int_model)
|
||||||
|
int_opts = int_model._meta
|
||||||
|
connection = (alias, int_opts.db_table, link_field.column, int_opts.pk.column)
|
||||||
|
alias = seen[int_model] = self.join(connection, nullable=False,
|
||||||
|
join_field=link_field)
|
||||||
|
return alias
|
||||||
|
|
||||||
def remove_inherited_models(self):
|
def remove_inherited_models(self):
|
||||||
"""
|
"""
|
||||||
Undoes the effects of setup_inherited_models(). Should be called
|
Undoes the effects of setup_inherited_models(). Should be called
|
||||||
|
|
Loading…
Reference in New Issue