Removed join() promote kwarg

The join promote=True was over-aggressive in select_related handling.
After that was removed, the only other user was query.combine(). That
use case is very easy to handle locally, so there is no more need for
the join(promote=True) flag.

Refs #19849.
This commit is contained in:
Anssi Kääriäinen 2013-02-19 04:47:47 +02:00
parent 3fef304ff2
commit edf93127bf
3 changed files with 34 additions and 18 deletions

View File

@ -620,7 +620,7 @@ class SQLCompiler(object):
alias = self.query.join((alias, table, f.column,
f.rel.get_related_field().column),
promote=promote, join_field=f)
outer_if_first=promote, join_field=f)
columns, aliases = self.get_default_columns(start_alias=alias,
opts=f.rel.to._meta, as_pairs=True)
self.query.related_select_cols.extend(
@ -648,7 +648,7 @@ class SQLCompiler(object):
table = model._meta.db_table
alias = self.query.join(
(alias, table, f.rel.get_related_field().column, f.column),
promote=True, join_field=f
outer_if_first=True, join_field=f
)
from_parent = (opts.model if issubclass(model, opts.model)
else None)

View File

@ -507,9 +507,11 @@ class Query(object):
# updated alias.
lhs = change_map.get(lhs, lhs)
new_alias = self.join(
(lhs, table, lhs_col, col), reuse=reuse, promote=promote,
(lhs, table, lhs_col, col), reuse=reuse,
outer_if_first=not conjunction, nullable=nullable,
join_field=join_field)
if promote:
self.promote_joins([new_alias])
# We can't reuse the same join again in the query. If we have two
# distinct joins for the same connection in rhs query, then the
# combined query must have two joins, too.
@ -914,8 +916,8 @@ class Query(object):
"""
return len([1 for count in self.alias_refcount.values() if count])
def join(self, connection, reuse=None, promote=False,
outer_if_first=False, nullable=False, join_field=None):
def join(self, connection, reuse=None, outer_if_first=False,
nullable=False, join_field=None):
"""
Returns an alias for the join in 'connection', either reusing an
existing alias for that join or creating a new one. 'connection' is a
@ -929,14 +931,8 @@ class Query(object):
(matching the connection) are reusable, or it can be a set containing
the aliases that can be reused.
If 'promote' is True, the join type for the alias will be LOUTER (if
the alias previously existed, the join type will be promoted from INNER
to LOUTER, if necessary).
If 'outer_if_first' is True and a new join is created, it will have the
LOUTER join type. Used for example when adding ORed filters, where we
want to use LOUTER joins except if some other join already restricts
the join to INNER join.
LOUTER join type.
A join is always created as LOUTER if the lhs alias is LOUTER to make
sure we do not generate chains like t1 LOUTER t2 INNER t3.
@ -961,8 +957,6 @@ class Query(object):
# join_field used for the under work join.
continue
self.ref_alias(alias)
if promote or (lhs and self.alias_map[lhs].join_type == self.LOUTER):
self.promote_joins([alias])
return alias
# No reuse is possible, so we need a new alias.
@ -971,10 +965,9 @@ class Query(object):
# Not all tables need to be joined to anything. No join type
# means the later columns are ignored.
join_type = None
elif (promote or outer_if_first
or self.alias_map[lhs].join_type == self.LOUTER):
# We need to use LOUTER join if asked by promote or outer_if_first,
# or if the LHS table is left-joined in the query.
elif outer_if_first or self.alias_map[lhs].join_type == self.LOUTER:
# We need to use LOUTER join if asked by outer_if_first or if the
# LHS table is left-joined in the query.
join_type = self.LOUTER
else:
join_type = self.INNER

View File

@ -139,3 +139,26 @@ class SelectRelatedRegressTests(TestCase):
self.assertEqual(troy.name, 'Troy Buswell')
self.assertEqual(troy.value, 42)
self.assertEqual(troy.state.name, 'Western Australia')
def test_null_join_promotion(self):
australia = Country.objects.create(name='Australia')
active = ClientStatus.objects.create(name='active')
wa = State.objects.create(name="Western Australia", country=australia)
bob = Client.objects.create(name='Bob', status=active)
jack = Client.objects.create(name='Jack', status=active, state=wa)
qs = Client.objects.filter(state=wa).select_related('state')
with self.assertNumQueries(1):
self.assertEqual(list(qs), [jack])
self.assertEqual(qs[0].state, wa)
# The select_related join wasn't promoted as there was already an
# existing (even if trimmed) inner join to state.
self.assertFalse('LEFT OUTER' in str(qs.query))
qs = Client.objects.select_related('state').order_by('name')
with self.assertNumQueries(1):
self.assertEqual(list(qs), [bob, jack])
self.assertIs(qs[0].state, None)
self.assertEqual(qs[1].state, wa)
# The select_related join was promoted as there is already an
# existing join.
self.assertTrue('LEFT OUTER' in str(qs.query))