mirror of
https://github.com/django/django.git
synced 2025-02-02 21:59:53 +00:00
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:
parent
3fef304ff2
commit
edf93127bf
@ -620,7 +620,7 @@ class SQLCompiler(object):
|
|||||||
|
|
||||||
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),
|
||||||
promote=promote, join_field=f)
|
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(
|
||||||
@ -648,7 +648,7 @@ class SQLCompiler(object):
|
|||||||
table = model._meta.db_table
|
table = model._meta.db_table
|
||||||
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
|
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)
|
||||||
|
@ -507,9 +507,11 @@ class Query(object):
|
|||||||
# updated alias.
|
# updated alias.
|
||||||
lhs = change_map.get(lhs, lhs)
|
lhs = change_map.get(lhs, lhs)
|
||||||
new_alias = self.join(
|
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,
|
outer_if_first=not conjunction, nullable=nullable,
|
||||||
join_field=join_field)
|
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
|
# 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
|
# distinct joins for the same connection in rhs query, then the
|
||||||
# combined query must have two joins, too.
|
# 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])
|
return len([1 for count in self.alias_refcount.values() if count])
|
||||||
|
|
||||||
def join(self, connection, reuse=None, promote=False,
|
def join(self, connection, reuse=None, outer_if_first=False,
|
||||||
outer_if_first=False, nullable=False, join_field=None):
|
nullable=False, join_field=None):
|
||||||
"""
|
"""
|
||||||
Returns an alias for the join in 'connection', either reusing an
|
Returns an alias for the join in 'connection', either reusing an
|
||||||
existing alias for that join or creating a new one. 'connection' is a
|
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
|
(matching the connection) are reusable, or it can be a set containing
|
||||||
the aliases that can be reused.
|
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
|
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
|
LOUTER join type.
|
||||||
want to use LOUTER joins except if some other join already restricts
|
|
||||||
the join to INNER join.
|
|
||||||
|
|
||||||
A join is always created as LOUTER if the lhs alias is LOUTER to make
|
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.
|
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.
|
# join_field used for the under work join.
|
||||||
continue
|
continue
|
||||||
self.ref_alias(alias)
|
self.ref_alias(alias)
|
||||||
if promote or (lhs and self.alias_map[lhs].join_type == self.LOUTER):
|
|
||||||
self.promote_joins([alias])
|
|
||||||
return alias
|
return alias
|
||||||
|
|
||||||
# No reuse is possible, so we need a new 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
|
# Not all tables need to be joined to anything. No join type
|
||||||
# means the later columns are ignored.
|
# means the later columns are ignored.
|
||||||
join_type = None
|
join_type = None
|
||||||
elif (promote or outer_if_first
|
elif outer_if_first or self.alias_map[lhs].join_type == self.LOUTER:
|
||||||
or self.alias_map[lhs].join_type == self.LOUTER):
|
# We need to use LOUTER join if asked by outer_if_first or if the
|
||||||
# We need to use LOUTER join if asked by promote or outer_if_first,
|
# LHS table is left-joined in the query.
|
||||||
# or if the LHS table is left-joined in the query.
|
|
||||||
join_type = self.LOUTER
|
join_type = self.LOUTER
|
||||||
else:
|
else:
|
||||||
join_type = self.INNER
|
join_type = self.INNER
|
||||||
|
@ -139,3 +139,26 @@ class SelectRelatedRegressTests(TestCase):
|
|||||||
self.assertEqual(troy.name, 'Troy Buswell')
|
self.assertEqual(troy.name, 'Troy Buswell')
|
||||||
self.assertEqual(troy.value, 42)
|
self.assertEqual(troy.value, 42)
|
||||||
self.assertEqual(troy.state.name, 'Western Australia')
|
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))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user