mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
queryset-refactor: Create a new join when merging two QuerySets that use a 1-m
field. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6492 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
8926b431ed
commit
142e400c5c
@ -48,6 +48,7 @@ RHS_JOIN_COL = 5
|
||||
ALIAS_TABLE = 0
|
||||
ALIAS_REFCOUNT = 1
|
||||
ALIAS_JOIN = 2
|
||||
ALIAS_MERGE_SEP = 3
|
||||
|
||||
# How many results to expect from a cursor.execute call
|
||||
MULTI = 'multi'
|
||||
@ -252,8 +253,10 @@ class Query(object):
|
||||
continue
|
||||
promote = (rhs.alias_map[alias][ALIAS_JOIN][JOIN_TYPE] ==
|
||||
self.LOUTER)
|
||||
merge_separate = (connection == AND)
|
||||
new_alias = self.join(rhs.rev_join_map[alias], exclusions=used,
|
||||
promote=promote, outer_if_first=True)
|
||||
promote=promote, outer_if_first=True,
|
||||
merge_separate=merge_separate)
|
||||
if self.alias_map[alias][ALIAS_REFCOUNT] == 1:
|
||||
first_new_join = False
|
||||
used[new_alias] = None
|
||||
@ -417,7 +420,7 @@ class Query(object):
|
||||
alias = table_name
|
||||
else:
|
||||
alias = '%s%d' % (self.alias_prefix, len(self.alias_map) + 1)
|
||||
self.alias_map[alias] = [table_name, 1, None]
|
||||
self.alias_map[alias] = [table_name, 1, None, False]
|
||||
self.table_map.setdefault(table_name, []).append(alias)
|
||||
self.tables.append(alias)
|
||||
return alias, True
|
||||
@ -435,7 +438,8 @@ class Query(object):
|
||||
self.alias_map[alias][ALIAS_JOIN][JOIN_TYPE] = self.LOUTER
|
||||
|
||||
def join(self, (lhs, table, lhs_col, col), always_create=False,
|
||||
exclusions=(), promote=False, outer_if_first=False):
|
||||
exclusions=(), promote=False, outer_if_first=False,
|
||||
merge_separate=False):
|
||||
"""
|
||||
Returns an alias for a join between 'table' and 'lhs' on the given
|
||||
columns, either reusing an existing alias for that join or creating a
|
||||
@ -456,6 +460,10 @@ class Query(object):
|
||||
If 'outer_if_first' is True and a new join is created, it will have the
|
||||
LOUTER join type. This is used when joining certain types of querysets
|
||||
and Q-objects together.
|
||||
|
||||
If the 'merge_separate' parameter is True, we create a new alias if we
|
||||
would otherwise reuse an alias that also had 'merge_separate' set to
|
||||
True when it was created.
|
||||
"""
|
||||
if lhs not in self.alias_map:
|
||||
lhs_table = lhs
|
||||
@ -467,7 +475,9 @@ class Query(object):
|
||||
aliases = self.join_map.get(t_ident)
|
||||
if aliases and not always_create:
|
||||
for alias in aliases:
|
||||
if alias not in exclusions:
|
||||
if (alias not in exclusions and
|
||||
not (merge_separate and
|
||||
self.alias_map[alias][ALIAS_MERGE_SEP])):
|
||||
self.ref_alias(alias)
|
||||
if promote:
|
||||
self.alias_map[alias][ALIAS_JOIN][JOIN_TYPE] = \
|
||||
@ -487,6 +497,7 @@ class Query(object):
|
||||
# means the later columns are ignored.
|
||||
join[JOIN_TYPE] = None
|
||||
self.alias_map[alias][ALIAS_JOIN] = join
|
||||
self.alias_map[alias][ALIAS_MERGE_SEP] = merge_separate
|
||||
self.join_map.setdefault(t_ident, []).append(alias)
|
||||
self.rev_join_map[alias] = t_ident
|
||||
return alias
|
||||
@ -647,7 +658,7 @@ class Query(object):
|
||||
opts.pk.column, field.m2m_column_name()), dupe_multis)
|
||||
far_alias = self.join((int_alias, remote_opts.db_table,
|
||||
field.m2m_reverse_name(), remote_opts.pk.column),
|
||||
dupe_multis)
|
||||
dupe_multis, merge_separate=True)
|
||||
return ([int_alias, far_alias], remote_opts, field, remote_opts.pk,
|
||||
None)
|
||||
|
||||
@ -661,7 +672,7 @@ class Query(object):
|
||||
opts.pk.column, field.m2m_reverse_name()), dupe_multis)
|
||||
far_alias = self.join((int_alias, remote_opts.db_table,
|
||||
field.m2m_column_name(), remote_opts.pk.column),
|
||||
dupe_multis)
|
||||
dupe_multis, merge_separate=True)
|
||||
# XXX: Why is the final component able to be None here?
|
||||
return ([int_alias, far_alias], remote_opts, field, remote_opts.pk,
|
||||
None)
|
||||
@ -673,7 +684,8 @@ class Query(object):
|
||||
field = field.field
|
||||
local_field = opts.get_field(field.rel.field_name)
|
||||
alias = self.join((root_alias, remote_opts.db_table,
|
||||
local_field.column, field.column), dupe_multis)
|
||||
local_field.column, field.column), dupe_multis,
|
||||
merge_separate=True)
|
||||
return ([alias], remote_opts, field, field, remote_opts.pk.column)
|
||||
|
||||
|
||||
|
@ -81,11 +81,8 @@ Bug #1801
|
||||
[<Author: a2>]
|
||||
>>> Author.objects.filter(item=i3)
|
||||
[<Author: a2>]
|
||||
|
||||
# FIXME: When we join these queries, we MUST NOT share the table joins. this is
|
||||
# the case for all m-to-m and 1-to-m joins (but m-to-1 is fine).
|
||||
# >>> Author.objects.filter(item=i2) & Author.objects.filter(item=i3)
|
||||
# [<Author: a2>]
|
||||
>>> Author.objects.filter(item=i2) & Author.objects.filter(item=i3)
|
||||
[<Author: a2>]
|
||||
|
||||
Bug #2306
|
||||
Checking that no join types are "left outer" joins.
|
||||
|
Loading…
x
Reference in New Issue
Block a user