1
0
mirror of https://github.com/django/django.git synced 2025-03-06 15:32:33 +00:00

Fixed #20583 -- ORM always uses setup_joins() for join generation

There were a couple of places which used Query.join() directly. By
using setup_joins() in these places the code is more DRY, and in
addition there is no need to directly call field.get_joining_columns()
unless the field is the given join_field from get_path_info(). This
makes it easier to make sure a ForeignObject subclass generates joins
correctly in all cases.
This commit is contained in:
Anssi Kääriäinen 2013-06-15 20:31:46 +03:00
parent b3532f7df9
commit aa22cbd51a
2 changed files with 19 additions and 23 deletions

View File

@ -631,12 +631,10 @@ class SQLCompiler(object):
if not select_related_descend(f, restricted, requested, if not select_related_descend(f, restricted, requested,
only_load.get(field_model)): only_load.get(field_model)):
continue continue
table = f.rel.to._meta.db_table
promote = nullable or f.null promote = nullable or f.null
alias = self.query.join_parent_model(opts, model, root_alias, {}) _, _, _, joins, _ = self.query.setup_joins(
join_cols = f.get_joining_columns() [f.name], opts, root_alias, outer_if_first=promote)
alias = self.query.join((alias, table, join_cols), alias = joins[-1]
outer_if_first=promote, join_field=f)
columns, aliases = self.get_default_columns(start_alias=alias, columns, aliases = self.get_default_columns(start_alias=alias,
opts=f.rel.to._meta, as_pairs=True) opts=f.rel.to._meta, as_pairs=True)
self.query.related_select_cols.extend( self.query.related_select_cols.extend(
@ -660,12 +658,9 @@ 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, {}) _, _, _, joins, _ = self.query.setup_joins(
table = model._meta.db_table [f.related_query_name()], opts, root_alias, outer_if_first=True)
alias = self.query.join( alias = joins[-1]
(alias, table, f.get_joining_columns(reverse_join=True)),
outer_if_first=True, join_field=f
)
from_parent = (opts.model if issubclass(model, opts.model) from_parent = (opts.model if issubclass(model, opts.model)
else None) else None)
columns, aliases = self.get_default_columns(start_alias=alias, columns, aliases = self.get_default_columns(start_alias=alias,
@ -677,7 +672,7 @@ class SQLCompiler(object):
# Use True here because we are looking at the _reverse_ side of # Use True here because we are looking at the _reverse_ side of
# the relation, which is always nullable. # the relation, which is always nullable.
new_nullable = True new_nullable = True
table = model._meta.db_table
self.fill_related_selections(model._meta, table, cur_depth+1, self.fill_related_selections(model._meta, table, cur_depth+1,
next, restricted, new_nullable) next, restricted, new_nullable)

View File

@ -926,10 +926,10 @@ class Query(object):
""" """
if model in seen: if model in seen:
return seen[model] return seen[model]
int_opts = opts
chain = opts.get_base_chain(model) chain = opts.get_base_chain(model)
if chain is None: if chain is None:
return alias return alias
curr_opts = opts
for int_model in chain: for int_model in chain:
if int_model in seen: if int_model in seen:
return seen[int_model] return seen[int_model]
@ -937,14 +937,14 @@ class Query(object):
# with no parents, assign the new options # with no parents, assign the new options
# object and skip to the next base in that # object and skip to the next base in that
# case # case
if not int_opts.parents[int_model]: if not curr_opts.parents[int_model]:
int_opts = int_model._meta curr_opts = int_model._meta
continue continue
link_field = int_opts.get_ancestor_link(int_model) link_field = curr_opts.get_ancestor_link(int_model)
int_opts = int_model._meta _, _, _, joins, _ = self.setup_joins(
connection = (alias, int_opts.db_table, link_field.get_joining_columns()) [link_field.name], curr_opts, alias)
alias = seen[int_model] = self.join(connection, nullable=False, curr_opts = int_model._meta
join_field=link_field) alias = seen[int_model] = joins[-1]
return alias or seen[None] return alias or seen[None]
def remove_inherited_models(self): def remove_inherited_models(self):
@ -1321,7 +1321,7 @@ class Query(object):
return path, final_field, targets return path, final_field, targets
def setup_joins(self, names, opts, alias, can_reuse=None, allow_many=True, def setup_joins(self, names, opts, alias, can_reuse=None, allow_many=True,
allow_explicit_fk=False): allow_explicit_fk=False, outer_if_first=False):
""" """
Compute the necessary table joins for the passage through the fields Compute the necessary table joins for the passage through the fields
given in 'names'. 'opts' is the Options class for the current model given in 'names'. 'opts' is the Options class for the current model
@ -1364,8 +1364,9 @@ class Query(object):
nullable = True nullable = True
connection = alias, opts.db_table, join.join_field.get_joining_columns() connection = alias, opts.db_table, join.join_field.get_joining_columns()
reuse = can_reuse if join.m2m else None reuse = can_reuse if join.m2m else None
alias = self.join(connection, reuse=reuse, alias = self.join(
nullable=nullable, join_field=join.join_field) connection, reuse=reuse, nullable=nullable, join_field=join.join_field,
outer_if_first=outer_if_first)
joins.append(alias) joins.append(alias)
if hasattr(final_field, 'field'): if hasattr(final_field, 'field'):
final_field = final_field.field final_field = final_field.field