summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnssi Kääriäinen <akaariai@gmail.com>2012-12-17 14:02:41 +0200
committerAnssi Kääriäinen <akaariai@gmail.com>2012-12-30 11:19:35 +0200
commit68985db48212c701a3d975636123a5d79bdc006f (patch)
tree9272ad672f0a9762dee77ba39a0888a5b003b5f3
parent4511aeb6b8b843ee913fb43a37c9686980210948 (diff)
Added Query.join_parent_model()
This simplifies especially compiler.py a lot, where almost the same code was repeated multiple times. Refs #19385
-rw-r--r--django/db/models/sql/compiler.py62
-rw-r--r--django/db/models/sql/query.py36
2 files changed, 37 insertions, 61 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index b0fb933705..16aa031e59 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -261,27 +261,14 @@ class SQLCompiler(object):
qn2 = self.connection.ops.quote_name
aliases = set()
only_load = self.deferred_to_columns()
-
+ seen = self.query.included_inherited_models.copy()
if start_alias:
- seen = {None: start_alias}
+ seen[None] = start_alias
for field, model in opts.get_fields_with_model():
if from_parent and model is not None and issubclass(from_parent, model):
# Avoid loading data for already loaded parents.
continue
- if start_alias:
- 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]
+ alias = self.query.join_parent_model(opts, model, start_alias, seen)
table = self.query.alias_map[alias].table_name
if table in only_load and field.column not in only_load[table]:
continue
@@ -623,26 +610,7 @@ class SQLCompiler(object):
continue
table = f.rel.to._meta.db_table
promote = nullable or f.null
- if model:
- 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_parent_model(opts, model, root_alias, {})
alias = self.query.join((alias, table, f.column,
f.rel.get_related_field().column),
@@ -670,28 +638,8 @@ class SQLCompiler(object):
only_load.get(model), reverse=True):
continue
+ alias = self.query.join_parent_model(opts, f.rel.to, root_alias, {})
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, table, f.rel.get_related_field().column, f.column),
promote=True, join_field=f
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index e5833b2b51..2546d6c889 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -1004,12 +1004,40 @@ class Query(object):
for field, model in opts.get_fields_with_model():
if model not in seen:
- link_field = opts.get_ancestor_link(model)
- seen[model] = self.join(
- (root_alias, model._meta.db_table, link_field.column,
- model._meta.pk.column), join_field=link_field)
+ self.join_parent_model(opts, model, root_alias, 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):
"""
Undoes the effects of setup_inherited_models(). Should be called