mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
queyrset-refactor: Some more speed-ups due to datastructure changes.
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7255 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
067d380e98
commit
133111e40b
@ -530,7 +530,11 @@ class ManyToOneRel(object):
|
|||||||
Returns the Field in the 'to' object to which this relationship is
|
Returns the Field in the 'to' object to which this relationship is
|
||||||
tied.
|
tied.
|
||||||
"""
|
"""
|
||||||
return self.to._meta.get_field_by_name(self.field_name, True)[0]
|
data = self.to._meta.get_field_by_name(self.field_name)
|
||||||
|
if not data[2]:
|
||||||
|
raise FieldDoesNotExist("No related field named '%s'" %
|
||||||
|
self.field_name)
|
||||||
|
return data[0]
|
||||||
|
|
||||||
class OneToOneRel(ManyToOneRel):
|
class OneToOneRel(ManyToOneRel):
|
||||||
def __init__(self, to, field_name, num_in_admin=0, min_num_in_admin=None,
|
def __init__(self, to, field_name, num_in_admin=0, min_num_in_admin=None,
|
||||||
|
@ -231,7 +231,7 @@ class Options(object):
|
|||||||
return f
|
return f
|
||||||
raise FieldDoesNotExist, '%s has no field named %r' % (self.object_name, name)
|
raise FieldDoesNotExist, '%s has no field named %r' % (self.object_name, name)
|
||||||
|
|
||||||
def get_field_by_name(self, name, only_direct=False):
|
def get_field_by_name(self, name):
|
||||||
"""
|
"""
|
||||||
Returns the (field_object, model, direct, m2m), where field_object is
|
Returns the (field_object, model, direct, m2m), where field_object is
|
||||||
the Field instance for the given name, model is the model containing
|
the Field instance for the given name, model is the model containing
|
||||||
@ -241,21 +241,17 @@ class Options(object):
|
|||||||
for this field (since the field doesn't have an instance associated
|
for this field (since the field doesn't have an instance associated
|
||||||
with it).
|
with it).
|
||||||
|
|
||||||
If 'only_direct' is True, only forwards relations (and non-relations)
|
|
||||||
are considered in the result.
|
|
||||||
|
|
||||||
Uses a cache internally, so after the first access, this is very fast.
|
Uses a cache internally, so after the first access, this is very fast.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
result = self._name_map.get(name)
|
try:
|
||||||
|
return self._name_map[name]
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
cache = self.init_name_map()
|
cache = self.init_name_map()
|
||||||
result = cache.get(name)
|
return self._name_map[name]
|
||||||
|
except KeyError:
|
||||||
if not result or (only_direct and not result[2]):
|
|
||||||
raise FieldDoesNotExist('%s has no field named %r'
|
raise FieldDoesNotExist('%s has no field named %r'
|
||||||
% (self.object_name, name))
|
% (self.object_name, name))
|
||||||
return result
|
|
||||||
|
|
||||||
def get_all_field_names(self):
|
def get_all_field_names(self):
|
||||||
"""
|
"""
|
||||||
|
@ -46,7 +46,8 @@ class Query(object):
|
|||||||
self.alias_refcount = {}
|
self.alias_refcount = {}
|
||||||
self.alias_map = {} # Maps alias to join information
|
self.alias_map = {} # Maps alias to join information
|
||||||
self.table_map = {} # Maps table names to list of aliases.
|
self.table_map = {} # Maps table names to list of aliases.
|
||||||
self.rev_join_map = {} # Reverse of join_map. (FIXME: Update comment)
|
self.join_map = {}
|
||||||
|
self.rev_join_map = {} # Reverse of join_map.
|
||||||
self.quote_cache = {}
|
self.quote_cache = {}
|
||||||
self.default_cols = True
|
self.default_cols = True
|
||||||
self.default_ordering = True
|
self.default_ordering = True
|
||||||
@ -130,6 +131,7 @@ class Query(object):
|
|||||||
obj.alias_refcount = self.alias_refcount.copy()
|
obj.alias_refcount = self.alias_refcount.copy()
|
||||||
obj.alias_map = self.alias_map.copy()
|
obj.alias_map = self.alias_map.copy()
|
||||||
obj.table_map = self.table_map.copy()
|
obj.table_map = self.table_map.copy()
|
||||||
|
obj.join_map = self.join_map.copy()
|
||||||
obj.rev_join_map = self.rev_join_map.copy()
|
obj.rev_join_map = self.rev_join_map.copy()
|
||||||
obj.quote_cache = {}
|
obj.quote_cache = {}
|
||||||
obj.default_cols = self.default_cols
|
obj.default_cols = self.default_cols
|
||||||
@ -271,7 +273,7 @@ class Query(object):
|
|||||||
|
|
||||||
# Work out how to relabel the rhs aliases, if necessary.
|
# Work out how to relabel the rhs aliases, if necessary.
|
||||||
change_map = {}
|
change_map = {}
|
||||||
used = {}
|
used = set()
|
||||||
conjunction = (connector == AND)
|
conjunction = (connector == AND)
|
||||||
first = True
|
first = True
|
||||||
for alias in rhs.tables:
|
for alias in rhs.tables:
|
||||||
@ -281,7 +283,7 @@ class Query(object):
|
|||||||
promote = (rhs.alias_map[alias][JOIN_TYPE] == self.LOUTER)
|
promote = (rhs.alias_map[alias][JOIN_TYPE] == self.LOUTER)
|
||||||
new_alias = self.join(rhs.rev_join_map[alias],
|
new_alias = self.join(rhs.rev_join_map[alias],
|
||||||
(conjunction and not first), used, promote, not conjunction)
|
(conjunction and not first), used, promote, not conjunction)
|
||||||
used[new_alias] = None
|
used.add(new_alias)
|
||||||
change_map[alias] = new_alias
|
change_map[alias] = new_alias
|
||||||
first = False
|
first = False
|
||||||
|
|
||||||
@ -411,22 +413,17 @@ class Query(object):
|
|||||||
"""
|
"""
|
||||||
result = []
|
result = []
|
||||||
qn = self.quote_name_unless_alias
|
qn = self.quote_name_unless_alias
|
||||||
|
qn2 = self.connection.ops.quote_name
|
||||||
first = True
|
first = True
|
||||||
for alias in self.tables:
|
for alias in self.tables:
|
||||||
if not self.alias_refcount[alias]:
|
if not self.alias_refcount[alias]:
|
||||||
continue
|
continue
|
||||||
join = self.alias_map[alias]
|
name, alias, join_type, lhs, lhs_col, col, nullable = self.alias_map[alias]
|
||||||
if join:
|
|
||||||
name, alias, join_type, lhs, lhs_col, col, nullable = join
|
|
||||||
alias_str = (alias != name and ' AS %s' % alias or '')
|
alias_str = (alias != name and ' AS %s' % alias or '')
|
||||||
else:
|
|
||||||
join_type = None
|
|
||||||
alias_str = ''
|
|
||||||
name = alias
|
|
||||||
if join_type and not first:
|
if join_type and not first:
|
||||||
result.append('%s %s%s ON (%s.%s = %s.%s)'
|
result.append('%s %s%s ON (%s.%s = %s.%s)'
|
||||||
% (join_type, qn(name), alias_str, qn(lhs),
|
% (join_type, qn(name), alias_str, qn(lhs),
|
||||||
qn(lhs_col), qn(alias), qn(col)))
|
qn2(lhs_col), qn(alias), qn2(col)))
|
||||||
else:
|
else:
|
||||||
connector = not first and ', ' or ''
|
connector = not first and ', ' or ''
|
||||||
result.append('%s%s%s' % (connector, qn(name), alias_str))
|
result.append('%s%s%s' % (connector, qn(name), alias_str))
|
||||||
@ -472,6 +469,7 @@ class Query(object):
|
|||||||
else:
|
else:
|
||||||
ordering = self.order_by or self.model._meta.ordering
|
ordering = self.order_by or self.model._meta.ordering
|
||||||
qn = self.quote_name_unless_alias
|
qn = self.quote_name_unless_alias
|
||||||
|
qn2 = self.connection.ops.quote_name
|
||||||
distinct = self.distinct
|
distinct = self.distinct
|
||||||
select_aliases = self._select_aliases
|
select_aliases = self._select_aliases
|
||||||
result = []
|
result = []
|
||||||
@ -492,12 +490,11 @@ class Query(object):
|
|||||||
result.append('%s %s' % (field, order))
|
result.append('%s %s' % (field, order))
|
||||||
continue
|
continue
|
||||||
if '.' in field:
|
if '.' in field:
|
||||||
# This came in through an extra(ordering=...) addition. Pass it
|
# This came in through an extra(order_by=...) addition. Pass it
|
||||||
# on verbatim, after mapping the table name to an alias, if
|
# on verbatim.
|
||||||
# necessary.
|
|
||||||
col, order = get_order_dir(field, asc)
|
col, order = get_order_dir(field, asc)
|
||||||
table, col = col.split('.', 1)
|
table, col = col.split('.', 1)
|
||||||
elt = '%s.%s' % (qn(self.table_alias(table)[0]), col)
|
elt = '%s.%s' % (qn(table), col)
|
||||||
if not distinct or elt in select_aliases:
|
if not distinct or elt in select_aliases:
|
||||||
result.append('%s %s' % (elt, order))
|
result.append('%s %s' % (elt, order))
|
||||||
elif get_order_dir(field)[0] not in self.extra_select:
|
elif get_order_dir(field)[0] not in self.extra_select:
|
||||||
@ -505,7 +502,7 @@ class Query(object):
|
|||||||
# '-field1__field2__field', etc.
|
# '-field1__field2__field', etc.
|
||||||
for table, col, order in self.find_ordering_name(field,
|
for table, col, order in self.find_ordering_name(field,
|
||||||
self.model._meta, default_order=asc):
|
self.model._meta, default_order=asc):
|
||||||
elt = '%s.%s' % (qn(table), qn(col))
|
elt = '%s.%s' % (qn(table), qn2(col))
|
||||||
if not distinct or elt in select_aliases:
|
if not distinct or elt in select_aliases:
|
||||||
result.append('%s %s' % (elt, order))
|
result.append('%s %s' % (elt, order))
|
||||||
else:
|
else:
|
||||||
@ -527,11 +524,11 @@ class Query(object):
|
|||||||
if not alias:
|
if not alias:
|
||||||
alias = self.get_initial_alias()
|
alias = self.get_initial_alias()
|
||||||
try:
|
try:
|
||||||
field, target, opts, joins = self.setup_joins(pieces, opts, alias,
|
field, target, opts, joins, last = self.setup_joins(pieces, opts,
|
||||||
False, False)
|
alias, False, False)
|
||||||
except JoinError:
|
except JoinError:
|
||||||
raise FieldError("Cannot order by many-valued field: '%s'" % name)
|
raise FieldError("Cannot order by many-valued field: '%s'" % name)
|
||||||
alias = joins[-1][-1]
|
alias = joins[-1]
|
||||||
col = target.column
|
col = target.column
|
||||||
|
|
||||||
# If we get to this point and the field is a relation to another model,
|
# If we get to this point and the field is a relation to another model,
|
||||||
@ -540,7 +537,7 @@ class Query(object):
|
|||||||
# Firstly, avoid infinite loops.
|
# Firstly, avoid infinite loops.
|
||||||
if not already_seen:
|
if not already_seen:
|
||||||
already_seen = set()
|
already_seen = set()
|
||||||
join_tuple = tuple([tuple(j) for j in joins])
|
join_tuple = tuple(joins)
|
||||||
if join_tuple in already_seen:
|
if join_tuple in already_seen:
|
||||||
raise FieldError('Infinite loop caused by ordering.')
|
raise FieldError('Infinite loop caused by ordering.')
|
||||||
already_seen.add(join_tuple)
|
already_seen.add(join_tuple)
|
||||||
@ -570,20 +567,22 @@ class Query(object):
|
|||||||
If 'create' is true, a new alias is always created. Otherwise, the
|
If 'create' is true, a new alias is always created. Otherwise, the
|
||||||
most recently created alias for the table (if one exists) is reused.
|
most recently created alias for the table (if one exists) is reused.
|
||||||
"""
|
"""
|
||||||
if not create and table_name in self.table_map:
|
current = self.table_map.get(table_name)
|
||||||
alias = self.table_map[table_name][-1]
|
if not create and current:
|
||||||
|
alias = current[0]
|
||||||
self.alias_refcount[alias] += 1
|
self.alias_refcount[alias] += 1
|
||||||
return alias, False
|
return alias, False
|
||||||
|
|
||||||
# Create a new alias for this table.
|
# Create a new alias for this table.
|
||||||
if table_name not in self.table_map:
|
if current:
|
||||||
|
alias = '%s%d' % (self.alias_prefix, len(self.alias_map) + 1)
|
||||||
|
current.append(alias)
|
||||||
|
else:
|
||||||
# The first occurence of a table uses the table name directly.
|
# The first occurence of a table uses the table name directly.
|
||||||
alias = table_name
|
alias = table_name
|
||||||
else:
|
self.table_map[alias] = [alias]
|
||||||
alias = '%s%d' % (self.alias_prefix, len(self.alias_map) + 1)
|
|
||||||
self.alias_refcount[alias] = 1
|
self.alias_refcount[alias] = 1
|
||||||
self.alias_map[alias] = None
|
#self.alias_map[alias] = None
|
||||||
self.table_map.setdefault(table_name, []).append(alias)
|
|
||||||
self.tables.append(alias)
|
self.tables.append(alias)
|
||||||
return alias, True
|
return alias, True
|
||||||
|
|
||||||
@ -629,7 +628,9 @@ class Query(object):
|
|||||||
alias_data = list(self.alias_map[old_alias])
|
alias_data = list(self.alias_map[old_alias])
|
||||||
alias_data[RHS_ALIAS] = new_alias
|
alias_data[RHS_ALIAS] = new_alias
|
||||||
|
|
||||||
self.rev_join_map[new_alias] = self.rev_join_map[old_alias]
|
t = self.rev_join_map[old_alias]
|
||||||
|
self.join_map[t] = new_alias
|
||||||
|
self.rev_join_map[new_alias] = t
|
||||||
del self.rev_join_map[old_alias]
|
del self.rev_join_map[old_alias]
|
||||||
self.alias_refcount[new_alias] = self.alias_refcount[old_alias]
|
self.alias_refcount[new_alias] = self.alias_refcount[old_alias]
|
||||||
del self.alias_refcount[old_alias]
|
del self.alias_refcount[old_alias]
|
||||||
@ -654,7 +655,6 @@ class Query(object):
|
|||||||
data[LHS_ALIAS] = change_map[lhs]
|
data[LHS_ALIAS] = change_map[lhs]
|
||||||
self.alias_map[alias] = tuple(data)
|
self.alias_map[alias] = tuple(data)
|
||||||
|
|
||||||
|
|
||||||
def bump_prefix(self):
|
def bump_prefix(self):
|
||||||
"""
|
"""
|
||||||
Changes the alias prefix to the next letter in the alphabet and
|
Changes the alias prefix to the next letter in the alphabet and
|
||||||
@ -724,29 +724,19 @@ class Query(object):
|
|||||||
is a candidate for promotion (to "left outer") when combining querysets.
|
is a candidate for promotion (to "left outer") when combining querysets.
|
||||||
"""
|
"""
|
||||||
lhs, table, lhs_col, col = connection
|
lhs, table, lhs_col, col = connection
|
||||||
if lhs is None:
|
if lhs in self.alias_map:
|
||||||
lhs_table = None
|
|
||||||
is_table = False
|
|
||||||
elif lhs not in self.alias_map:
|
|
||||||
lhs_table = lhs
|
|
||||||
is_table = True
|
|
||||||
else:
|
|
||||||
lhs_table = self.alias_map[lhs][TABLE_NAME]
|
lhs_table = self.alias_map[lhs][TABLE_NAME]
|
||||||
is_table = False
|
else:
|
||||||
|
lhs_table = lhs
|
||||||
t_ident = (lhs_table, table, lhs_col, col)
|
t_ident = (lhs_table, table, lhs_col, col)
|
||||||
if not always_create:
|
alias = self.join_map.get(t_ident)
|
||||||
for alias, row in self.rev_join_map.items():
|
if alias and not always_create and alias not in exclusions:
|
||||||
if t_ident == row and alias not in exclusions:
|
|
||||||
self.ref_alias(alias)
|
self.ref_alias(alias)
|
||||||
if promote:
|
if promote:
|
||||||
self.promote_alias(alias)
|
self.promote_alias(alias)
|
||||||
return alias
|
return alias
|
||||||
# If we get to here (no non-excluded alias exists), we'll fall
|
|
||||||
# through to creating a new alias.
|
|
||||||
|
|
||||||
# No reuse is possible, so we need a new alias.
|
# No reuse is possible, so we need a new alias.
|
||||||
assert not is_table, \
|
|
||||||
"Must pass in lhs alias when creating a new join."
|
|
||||||
alias, _ = self.table_alias(table, True)
|
alias, _ = self.table_alias(table, True)
|
||||||
if not lhs:
|
if not lhs:
|
||||||
# Not all tables need to be joined to anything. No join type
|
# Not all tables need to be joined to anything. No join type
|
||||||
@ -758,6 +748,7 @@ class Query(object):
|
|||||||
join_type = self.INNER
|
join_type = self.INNER
|
||||||
join = (table, alias, join_type, lhs, lhs_col, col, nullable)
|
join = (table, alias, join_type, lhs, lhs_col, col, nullable)
|
||||||
self.alias_map[alias] = join
|
self.alias_map[alias] = join
|
||||||
|
self.join_map[t_ident] = alias
|
||||||
self.rev_join_map[alias] = t_ident
|
self.rev_join_map[alias] = t_ident
|
||||||
return alias
|
return alias
|
||||||
|
|
||||||
@ -855,22 +846,28 @@ class Query(object):
|
|||||||
allow_many = trim or not negate
|
allow_many = trim or not negate
|
||||||
|
|
||||||
try:
|
try:
|
||||||
field, target, opts, join_list = self.setup_joins(parts, opts,
|
field, target, opts, join_list, last = self.setup_joins(parts, opts,
|
||||||
alias, (connector == AND), allow_many)
|
alias, (connector == AND), allow_many)
|
||||||
except JoinError, e:
|
except JoinError, e:
|
||||||
self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level]))
|
self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level]))
|
||||||
return
|
return
|
||||||
|
final = len(join_list)
|
||||||
|
penultimate = last.pop()
|
||||||
|
if penultimate == final:
|
||||||
|
penultimate = last.pop()
|
||||||
if trim and len(join_list) > 1:
|
if trim and len(join_list) > 1:
|
||||||
extra = join_list[-1]
|
extra = join_list[penultimate:]
|
||||||
join_list = join_list[:-1]
|
join_list = join_list[:penultimate]
|
||||||
|
final = penultimate
|
||||||
|
penultimate = last.pop()
|
||||||
col = self.alias_map[extra[0]][LHS_JOIN_COL]
|
col = self.alias_map[extra[0]][LHS_JOIN_COL]
|
||||||
for alias in extra:
|
for alias in extra:
|
||||||
self.unref_alias(alias)
|
self.unref_alias(alias)
|
||||||
else:
|
else:
|
||||||
col = target.column
|
col = target.column
|
||||||
alias = join_list[-1][-1]
|
alias = join_list[-1]
|
||||||
|
|
||||||
if join_list:
|
if final > 1:
|
||||||
# An optimization: if the final join is against the same column as
|
# An optimization: if the final join is against the same column as
|
||||||
# we are comparing against, we can go back one step in the join
|
# we are comparing against, we can go back one step in the join
|
||||||
# chain and compare against the lhs of the join instead. The result
|
# chain and compare against the lhs of the join instead. The result
|
||||||
@ -880,18 +877,18 @@ class Query(object):
|
|||||||
self.unref_alias(alias)
|
self.unref_alias(alias)
|
||||||
alias = join[LHS_ALIAS]
|
alias = join[LHS_ALIAS]
|
||||||
col = join[LHS_JOIN_COL]
|
col = join[LHS_JOIN_COL]
|
||||||
if len(join_list[-1]) == 1:
|
|
||||||
join_list = join_list[:-1]
|
join_list = join_list[:-1]
|
||||||
else:
|
final -= 1
|
||||||
join_list[-1] = join_list[-1][:-1]
|
if final == penultimate:
|
||||||
|
penultimate = last.pop()
|
||||||
|
|
||||||
if (lookup_type == 'isnull' and value is True and not negate and
|
if (lookup_type == 'isnull' and value is True and not negate and
|
||||||
(len(join_list) > 1 or len(join_list[0]) > 1)):
|
final > 1):
|
||||||
# If the comparison is against NULL, we need to use a left outer
|
# If the comparison is against NULL, we need to use a left outer
|
||||||
# join when connecting to the previous model. We make that
|
# join when connecting to the previous model. We make that
|
||||||
# adjustment here. We don't do this unless needed as it's less
|
# adjustment here. We don't do this unless needed as it's less
|
||||||
# efficient at the database level.
|
# efficient at the database level.
|
||||||
self.promote_alias(join_list[-1][0])
|
self.promote_alias(join_list[penultimate])
|
||||||
|
|
||||||
if connector == OR:
|
if connector == OR:
|
||||||
# Some joins may need to be promoted when adding a new filter to a
|
# Some joins may need to be promoted when adding a new filter to a
|
||||||
@ -899,7 +896,7 @@ class Query(object):
|
|||||||
# from any previous joins (ref count is 1 in the table list), we
|
# from any previous joins (ref count is 1 in the table list), we
|
||||||
# make the new additions (and any existing ones not used in the new
|
# make the new additions (and any existing ones not used in the new
|
||||||
# join list) an outer join.
|
# join list) an outer join.
|
||||||
join_it = itertools.chain(*join_list)
|
join_it = iter(join_list)
|
||||||
table_it = iter(self.tables)
|
table_it = iter(self.tables)
|
||||||
join_it.next(), table_it.next()
|
join_it.next(), table_it.next()
|
||||||
for join in join_it:
|
for join in join_it:
|
||||||
@ -931,14 +928,11 @@ class Query(object):
|
|||||||
merged = False
|
merged = False
|
||||||
|
|
||||||
if negate:
|
if negate:
|
||||||
count = 0
|
for alias in join_list:
|
||||||
for join in join_list:
|
|
||||||
count += len(join)
|
|
||||||
for alias in join:
|
|
||||||
self.promote_alias(alias)
|
self.promote_alias(alias)
|
||||||
if not merged:
|
if not merged:
|
||||||
self.where.negate()
|
self.where.negate()
|
||||||
if count > 1 and lookup_type != 'isnull':
|
if final > 1 and lookup_type != 'isnull':
|
||||||
j_col = self.alias_map[alias][RHS_JOIN_COL]
|
j_col = self.alias_map[alias][RHS_JOIN_COL]
|
||||||
entry = Node([(alias, j_col, None, 'isnull', True)])
|
entry = Node([(alias, j_col, None, 'isnull', True)])
|
||||||
entry.negate()
|
entry.negate()
|
||||||
@ -989,10 +983,10 @@ class Query(object):
|
|||||||
column (used for any 'where' constraint), the final 'opts' value and the
|
column (used for any 'where' constraint), the final 'opts' value and the
|
||||||
list of tables joined.
|
list of tables joined.
|
||||||
"""
|
"""
|
||||||
joins = [[alias]]
|
joins = [alias]
|
||||||
used = set()
|
last = [0]
|
||||||
for pos, name in enumerate(names):
|
for pos, name in enumerate(names):
|
||||||
used.update(joins[-1])
|
last.append(len(joins))
|
||||||
if name == 'pk':
|
if name == 'pk':
|
||||||
name = opts.pk.name
|
name = opts.pk.name
|
||||||
|
|
||||||
@ -1011,8 +1005,7 @@ class Query(object):
|
|||||||
raise FieldError("Cannot resolve keyword %r into field. "
|
raise FieldError("Cannot resolve keyword %r into field. "
|
||||||
"Choices are: %s" % (name, ", ".join(names)))
|
"Choices are: %s" % (name, ", ".join(names)))
|
||||||
if not allow_many and (m2m or not direct):
|
if not allow_many and (m2m or not direct):
|
||||||
for join in joins:
|
for alias in joins:
|
||||||
for alias in join:
|
|
||||||
self.unref_alias(alias)
|
self.unref_alias(alias)
|
||||||
raise JoinError(pos + 1)
|
raise JoinError(pos + 1)
|
||||||
if model:
|
if model:
|
||||||
@ -1022,9 +1015,8 @@ class Query(object):
|
|||||||
lhs_col = opts.parents[int_model].column
|
lhs_col = opts.parents[int_model].column
|
||||||
opts = int_model._meta
|
opts = int_model._meta
|
||||||
alias = self.join((alias, opts.db_table, lhs_col,
|
alias = self.join((alias, opts.db_table, lhs_col,
|
||||||
opts.pk.column), exclusions=used)
|
opts.pk.column), exclusions=joins)
|
||||||
alias_list.append(alias)
|
joins.append(alias)
|
||||||
joins.append(alias_list)
|
|
||||||
cached_data = opts._join_cache.get(name)
|
cached_data = opts._join_cache.get(name)
|
||||||
orig_opts = opts
|
orig_opts = opts
|
||||||
|
|
||||||
@ -1048,10 +1040,10 @@ class Query(object):
|
|||||||
target)
|
target)
|
||||||
|
|
||||||
int_alias = self.join((alias, table1, from_col1, to_col1),
|
int_alias = self.join((alias, table1, from_col1, to_col1),
|
||||||
dupe_multis, used, nullable=True)
|
dupe_multis, joins, nullable=True)
|
||||||
alias = self.join((int_alias, table2, from_col2, to_col2),
|
alias = self.join((int_alias, table2, from_col2, to_col2),
|
||||||
dupe_multis, used, nullable=True)
|
dupe_multis, joins, nullable=True)
|
||||||
joins.append([int_alias, alias])
|
joins.extend([int_alias, alias])
|
||||||
elif field.rel:
|
elif field.rel:
|
||||||
# One-to-one or many-to-one field
|
# One-to-one or many-to-one field
|
||||||
if cached_data:
|
if cached_data:
|
||||||
@ -1066,8 +1058,8 @@ class Query(object):
|
|||||||
opts, target)
|
opts, target)
|
||||||
|
|
||||||
alias = self.join((alias, table, from_col, to_col),
|
alias = self.join((alias, table, from_col, to_col),
|
||||||
exclusions=used, nullable=field.null)
|
exclusions=joins, nullable=field.null)
|
||||||
joins.append([alias])
|
joins.append(alias)
|
||||||
else:
|
else:
|
||||||
# Non-relation fields.
|
# Non-relation fields.
|
||||||
target = field
|
target = field
|
||||||
@ -1094,10 +1086,10 @@ class Query(object):
|
|||||||
target)
|
target)
|
||||||
|
|
||||||
int_alias = self.join((alias, table1, from_col1, to_col1),
|
int_alias = self.join((alias, table1, from_col1, to_col1),
|
||||||
dupe_multis, used, nullable=True)
|
dupe_multis, joins, nullable=True)
|
||||||
alias = self.join((int_alias, table2, from_col2, to_col2),
|
alias = self.join((int_alias, table2, from_col2, to_col2),
|
||||||
dupe_multis, used, nullable=True)
|
dupe_multis, joins, nullable=True)
|
||||||
joins.append([int_alias, alias])
|
joins.extend([int_alias, alias])
|
||||||
else:
|
else:
|
||||||
# One-to-many field (ForeignKey defined on the target model)
|
# One-to-many field (ForeignKey defined on the target model)
|
||||||
if cached_data:
|
if cached_data:
|
||||||
@ -1114,13 +1106,13 @@ class Query(object):
|
|||||||
opts, target)
|
opts, target)
|
||||||
|
|
||||||
alias = self.join((alias, table, from_col, to_col),
|
alias = self.join((alias, table, from_col, to_col),
|
||||||
dupe_multis, used, nullable=True)
|
dupe_multis, joins, nullable=True)
|
||||||
joins.append([alias])
|
joins.append(alias)
|
||||||
|
|
||||||
if pos != len(names) - 1:
|
if pos != len(names) - 1:
|
||||||
raise FieldError("Join on field %r not permitted." % name)
|
raise FieldError("Join on field %r not permitted." % name)
|
||||||
|
|
||||||
return field, target, opts, joins
|
return field, target, opts, joins, last
|
||||||
|
|
||||||
def split_exclude(self, filter_expr, prefix):
|
def split_exclude(self, filter_expr, prefix):
|
||||||
"""
|
"""
|
||||||
@ -1179,9 +1171,10 @@ class Query(object):
|
|||||||
opts = self.get_meta()
|
opts = self.get_meta()
|
||||||
try:
|
try:
|
||||||
for name in field_names:
|
for name in field_names:
|
||||||
u1, target, u2, joins = self.setup_joins(name.split(LOOKUP_SEP),
|
u1, target, u2, joins, u3 = self.setup_joins(
|
||||||
opts, alias, False, allow_m2m, True)
|
name.split(LOOKUP_SEP), opts, alias, False, allow_m2m,
|
||||||
self.select.append((joins[-1][-1], target.column))
|
True)
|
||||||
|
self.select.append((joins[-1], target.column))
|
||||||
except JoinError:
|
except JoinError:
|
||||||
raise FieldError("Invalid field name: '%s'" % name)
|
raise FieldError("Invalid field name: '%s'" % name)
|
||||||
|
|
||||||
@ -1294,20 +1287,18 @@ class Query(object):
|
|||||||
"""
|
"""
|
||||||
opts = self.model._meta
|
opts = self.model._meta
|
||||||
alias = self.get_initial_alias()
|
alias = self.get_initial_alias()
|
||||||
field, col, opts, joins = self.setup_joins(start.split(LOOKUP_SEP),
|
field, col, opts, joins, last = self.setup_joins(
|
||||||
opts, alias, False)
|
start.split(LOOKUP_SEP), opts, alias, False)
|
||||||
alias = joins[-1][0]
|
alias = joins[last[-1]]
|
||||||
self.select = [(alias, self.alias_map[alias][RHS_JOIN_COL])]
|
self.select = [(alias, self.alias_map[alias][RHS_JOIN_COL])]
|
||||||
self.start_meta = opts
|
self.start_meta = opts
|
||||||
|
|
||||||
# The call to setup_joins add an extra reference to everything in
|
# The call to setup_joins add an extra reference to everything in
|
||||||
# joins. So we need to unref everything once, and everything prior to
|
# joins. So we need to unref everything once, and everything prior to
|
||||||
# the final join a second time.
|
# the final join a second time.
|
||||||
for join in joins[:-1]:
|
for alias in joins:
|
||||||
for alias in join:
|
|
||||||
self.unref_alias(alias)
|
self.unref_alias(alias)
|
||||||
self.unref_alias(alias)
|
for alias in joins[:last[-1]]:
|
||||||
for alias in joins[-1]:
|
|
||||||
self.unref_alias(alias)
|
self.unref_alias(alias)
|
||||||
|
|
||||||
def execute_sql(self, result_type=MULTI):
|
def execute_sql(self, result_type=MULTI):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user