mirror of
				https://github.com/django/django.git
				synced 2025-10-30 17:16:10 +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:
		| @@ -28,21 +28,21 @@ def add_lazy_relation(cls, field, relation): | ||||
|     """ | ||||
|     Adds a lookup on ``cls`` when a related field is defined using a string, | ||||
|     i.e.:: | ||||
|      | ||||
|  | ||||
|         class MyModel(Model): | ||||
|             fk = ForeignKey("AnotherModel") | ||||
|              | ||||
|  | ||||
|     This string can be: | ||||
|      | ||||
|  | ||||
|         * RECURSIVE_RELATIONSHIP_CONSTANT (i.e. "self") to indicate a recursive | ||||
|           relation. | ||||
|            | ||||
|  | ||||
|         * The name of a model (i.e "AnotherModel") to indicate another model in | ||||
|           the same app. | ||||
|            | ||||
|  | ||||
|         * An app-label and model name (i.e. "someapp.AnotherModel") to indicate | ||||
|           another model in a different app. | ||||
|            | ||||
|  | ||||
|     If the other model hasn't yet been loaded -- almost a given if you're using | ||||
|     lazy relationships -- then the relation won't be set up until the | ||||
|     class_prepared signal fires at the end of model initialization. | ||||
| @@ -51,7 +51,7 @@ def add_lazy_relation(cls, field, relation): | ||||
|     if relation == RECURSIVE_RELATIONSHIP_CONSTANT: | ||||
|         app_label = cls._meta.app_label | ||||
|         model_name = cls.__name__ | ||||
|      | ||||
|  | ||||
|     else: | ||||
|         # Look for an "app.Model" relation | ||||
|         try: | ||||
| @@ -60,10 +60,10 @@ def add_lazy_relation(cls, field, relation): | ||||
|             # If we can't split, assume a model in current app | ||||
|             app_label = cls._meta.app_label | ||||
|             model_name = relation | ||||
|      | ||||
|  | ||||
|     # Try to look up the related model, and if it's already loaded resolve the | ||||
|     # string right away. If get_model returns None, it means that the related | ||||
|     # model isn't loaded yet, so we need to pend the relation until the class  | ||||
|     # model isn't loaded yet, so we need to pend the relation until the class | ||||
|     # is prepared. | ||||
|     model = get_model(app_label, model_name, False) | ||||
|     if model: | ||||
| @@ -73,7 +73,7 @@ def add_lazy_relation(cls, field, relation): | ||||
|         key = (app_label, model_name) | ||||
|         value = (cls, field) | ||||
|         pending_lookups.setdefault(key, []).append(value) | ||||
|      | ||||
|  | ||||
| def do_pending_lookups(sender): | ||||
|     """ | ||||
|     Handle any pending relations to the sending model. Sent from class_prepared. | ||||
| @@ -530,7 +530,11 @@ class ManyToOneRel(object): | ||||
|         Returns the Field in the 'to' object to which this relationship is | ||||
|         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): | ||||
|     def __init__(self, to, field_name, num_in_admin=0, min_num_in_admin=None, | ||||
|   | ||||
| @@ -231,7 +231,7 @@ class Options(object): | ||||
|                 return f | ||||
|         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 | ||||
|         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 | ||||
|         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. | ||||
|         """ | ||||
|         try: | ||||
|             result = self._name_map.get(name) | ||||
|         except AttributeError: | ||||
|             cache = self.init_name_map() | ||||
|             result = cache.get(name) | ||||
|  | ||||
|         if not result or (only_direct and not result[2]): | ||||
|             try: | ||||
|                 return self._name_map[name] | ||||
|             except AttributeError: | ||||
|                 cache = self.init_name_map() | ||||
|                 return self._name_map[name] | ||||
|         except KeyError: | ||||
|             raise FieldDoesNotExist('%s has no field named %r' | ||||
|                     % (self.object_name, name)) | ||||
|         return result | ||||
|  | ||||
|     def get_all_field_names(self): | ||||
|         """ | ||||
|   | ||||
| @@ -46,7 +46,8 @@ class Query(object): | ||||
|         self.alias_refcount = {} | ||||
|         self.alias_map = {}     # Maps alias to join information | ||||
|         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.default_cols = True | ||||
|         self.default_ordering = True | ||||
| @@ -130,6 +131,7 @@ class Query(object): | ||||
|         obj.alias_refcount = self.alias_refcount.copy() | ||||
|         obj.alias_map = self.alias_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.quote_cache = {} | ||||
|         obj.default_cols = self.default_cols | ||||
| @@ -271,7 +273,7 @@ class Query(object): | ||||
|  | ||||
|         # Work out how to relabel the rhs aliases, if necessary. | ||||
|         change_map = {} | ||||
|         used = {} | ||||
|         used = set() | ||||
|         conjunction = (connector == AND) | ||||
|         first = True | ||||
|         for alias in rhs.tables: | ||||
| @@ -281,7 +283,7 @@ class Query(object): | ||||
|             promote = (rhs.alias_map[alias][JOIN_TYPE] == self.LOUTER) | ||||
|             new_alias = self.join(rhs.rev_join_map[alias], | ||||
|                     (conjunction and not first), used, promote, not conjunction) | ||||
|             used[new_alias] = None | ||||
|             used.add(new_alias) | ||||
|             change_map[alias] = new_alias | ||||
|             first = False | ||||
|  | ||||
| @@ -411,22 +413,17 @@ class Query(object): | ||||
|         """ | ||||
|         result = [] | ||||
|         qn = self.quote_name_unless_alias | ||||
|         qn2 = self.connection.ops.quote_name | ||||
|         first = True | ||||
|         for alias in self.tables: | ||||
|             if not self.alias_refcount[alias]: | ||||
|                 continue | ||||
|             join = 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 '') | ||||
|             else: | ||||
|                 join_type = None | ||||
|                 alias_str = '' | ||||
|                 name = alias | ||||
|             name, alias, join_type, lhs, lhs_col, col, nullable = self.alias_map[alias] | ||||
|             alias_str = (alias != name and ' AS %s' % alias or '') | ||||
|             if join_type and not first: | ||||
|                 result.append('%s %s%s ON (%s.%s = %s.%s)' | ||||
|                         % (join_type, qn(name), alias_str, qn(lhs), | ||||
|                            qn(lhs_col), qn(alias), qn(col))) | ||||
|                            qn2(lhs_col), qn(alias), qn2(col))) | ||||
|             else: | ||||
|                 connector = not first and ', ' or '' | ||||
|                 result.append('%s%s%s' % (connector, qn(name), alias_str)) | ||||
| @@ -472,6 +469,7 @@ class Query(object): | ||||
|         else: | ||||
|             ordering = self.order_by or self.model._meta.ordering | ||||
|         qn = self.quote_name_unless_alias | ||||
|         qn2 = self.connection.ops.quote_name | ||||
|         distinct = self.distinct | ||||
|         select_aliases = self._select_aliases | ||||
|         result = [] | ||||
| @@ -492,12 +490,11 @@ class Query(object): | ||||
|                 result.append('%s %s' % (field, order)) | ||||
|                 continue | ||||
|             if '.' in field: | ||||
|                 # This came in through an extra(ordering=...) addition. Pass it | ||||
|                 # on verbatim, after mapping the table name to an alias, if | ||||
|                 # necessary. | ||||
|                 # This came in through an extra(order_by=...) addition. Pass it | ||||
|                 # on verbatim. | ||||
|                 col, order = get_order_dir(field, asc) | ||||
|                 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: | ||||
|                     result.append('%s %s' % (elt, order)) | ||||
|             elif get_order_dir(field)[0] not in self.extra_select: | ||||
| @@ -505,7 +502,7 @@ class Query(object): | ||||
|                 # '-field1__field2__field', etc. | ||||
|                 for table, col, order in self.find_ordering_name(field, | ||||
|                         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: | ||||
|                         result.append('%s %s' % (elt, order)) | ||||
|             else: | ||||
| @@ -527,11 +524,11 @@ class Query(object): | ||||
|         if not alias: | ||||
|             alias = self.get_initial_alias() | ||||
|         try: | ||||
|             field, target, opts, joins = self.setup_joins(pieces, opts, alias, | ||||
|                     False, False) | ||||
|             field, target, opts, joins, last = self.setup_joins(pieces, opts, | ||||
|                     alias, False, False) | ||||
|         except JoinError: | ||||
|             raise FieldError("Cannot order by many-valued field: '%s'" % name) | ||||
|         alias = joins[-1][-1] | ||||
|         alias = joins[-1] | ||||
|         col = target.column | ||||
|  | ||||
|         # 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. | ||||
|             if not already_seen: | ||||
|                 already_seen = set() | ||||
|             join_tuple = tuple([tuple(j) for j in joins]) | ||||
|             join_tuple = tuple(joins) | ||||
|             if join_tuple in already_seen: | ||||
|                 raise FieldError('Infinite loop caused by ordering.') | ||||
|             already_seen.add(join_tuple) | ||||
| @@ -570,20 +567,22 @@ class Query(object): | ||||
|         If 'create' is true, a new alias is always created. Otherwise, the | ||||
|         most recently created alias for the table (if one exists) is reused. | ||||
|         """ | ||||
|         if not create and table_name in self.table_map: | ||||
|             alias = self.table_map[table_name][-1] | ||||
|         current = self.table_map.get(table_name) | ||||
|         if not create and current: | ||||
|             alias = current[0] | ||||
|             self.alias_refcount[alias] += 1 | ||||
|             return alias, False | ||||
|  | ||||
|         # 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. | ||||
|             alias = table_name | ||||
|         else: | ||||
|             alias = '%s%d' % (self.alias_prefix, len(self.alias_map) + 1) | ||||
|             self.table_map[alias] = [alias] | ||||
|         self.alias_refcount[alias] = 1 | ||||
|         self.alias_map[alias] = None | ||||
|         self.table_map.setdefault(table_name, []).append(alias) | ||||
|         #self.alias_map[alias] = None | ||||
|         self.tables.append(alias) | ||||
|         return alias, True | ||||
|  | ||||
| @@ -629,7 +628,9 @@ class Query(object): | ||||
|             alias_data = list(self.alias_map[old_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] | ||||
|             self.alias_refcount[new_alias] = self.alias_refcount[old_alias] | ||||
|             del self.alias_refcount[old_alias] | ||||
| @@ -654,7 +655,6 @@ class Query(object): | ||||
|                 data[LHS_ALIAS] = change_map[lhs] | ||||
|                 self.alias_map[alias] = tuple(data) | ||||
|  | ||||
|  | ||||
|     def bump_prefix(self): | ||||
|         """ | ||||
|         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. | ||||
|         """ | ||||
|         lhs, table, lhs_col, col = connection | ||||
|         if lhs is None: | ||||
|             lhs_table = None | ||||
|             is_table = False | ||||
|         elif lhs not in self.alias_map: | ||||
|             lhs_table = lhs | ||||
|             is_table = True | ||||
|         else: | ||||
|         if lhs in self.alias_map: | ||||
|             lhs_table = self.alias_map[lhs][TABLE_NAME] | ||||
|             is_table = False | ||||
|         else: | ||||
|             lhs_table = lhs | ||||
|         t_ident = (lhs_table, table, lhs_col, col) | ||||
|         if not always_create: | ||||
|             for alias, row in self.rev_join_map.items(): | ||||
|                 if t_ident == row and alias not in exclusions: | ||||
|                     self.ref_alias(alias) | ||||
|                     if promote: | ||||
|                         self.promote_alias(alias) | ||||
|                     return alias | ||||
|             # If we get to here (no non-excluded alias exists), we'll fall | ||||
|             # through to creating a new alias. | ||||
|         alias = self.join_map.get(t_ident) | ||||
|         if alias and not always_create and alias not in exclusions: | ||||
|             self.ref_alias(alias) | ||||
|             if promote: | ||||
|                 self.promote_alias(alias) | ||||
|             return 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) | ||||
|         if not lhs: | ||||
|             # Not all tables need to be joined to anything. No join type | ||||
| @@ -758,6 +748,7 @@ class Query(object): | ||||
|             join_type = self.INNER | ||||
|         join = (table, alias, join_type, lhs, lhs_col, col, nullable) | ||||
|         self.alias_map[alias] = join | ||||
|         self.join_map[t_ident] = alias | ||||
|         self.rev_join_map[alias] = t_ident | ||||
|         return alias | ||||
|  | ||||
| @@ -855,22 +846,28 @@ class Query(object): | ||||
|         allow_many = trim or not negate | ||||
|  | ||||
|         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) | ||||
|         except JoinError, e: | ||||
|             self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level])) | ||||
|             return | ||||
|         final = len(join_list) | ||||
|         penultimate = last.pop() | ||||
|         if penultimate == final: | ||||
|             penultimate = last.pop() | ||||
|         if trim and len(join_list) > 1: | ||||
|             extra = join_list[-1] | ||||
|             join_list = join_list[:-1] | ||||
|             extra = join_list[penultimate:] | ||||
|             join_list = join_list[:penultimate] | ||||
|             final = penultimate | ||||
|             penultimate = last.pop() | ||||
|             col = self.alias_map[extra[0]][LHS_JOIN_COL] | ||||
|             for alias in extra: | ||||
|                 self.unref_alias(alias) | ||||
|         else: | ||||
|             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 | ||||
|             # 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 | ||||
| @@ -880,18 +877,18 @@ class Query(object): | ||||
|                 self.unref_alias(alias) | ||||
|                 alias = join[LHS_ALIAS] | ||||
|                 col = join[LHS_JOIN_COL] | ||||
|                 if len(join_list[-1]) == 1: | ||||
|                     join_list = join_list[:-1] | ||||
|                 else: | ||||
|                     join_list[-1] = join_list[-1][:-1] | ||||
|                 join_list = join_list[:-1] | ||||
|                 final -= 1 | ||||
|                 if final == penultimate: | ||||
|                     penultimate = last.pop() | ||||
|  | ||||
|         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 | ||||
|             # join when connecting to the previous model. We make that | ||||
|             # adjustment here. We don't do this unless needed as it's less | ||||
|             # efficient at the database level. | ||||
|             self.promote_alias(join_list[-1][0]) | ||||
|             self.promote_alias(join_list[penultimate]) | ||||
|  | ||||
|         if connector == OR: | ||||
|             # 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 | ||||
|             # make the new additions (and any existing ones not used in the new | ||||
|             # join list) an outer join. | ||||
|             join_it = itertools.chain(*join_list) | ||||
|             join_it = iter(join_list) | ||||
|             table_it = iter(self.tables) | ||||
|             join_it.next(), table_it.next() | ||||
|             for join in join_it: | ||||
| @@ -931,14 +928,11 @@ class Query(object): | ||||
|             merged = False | ||||
|  | ||||
|         if negate: | ||||
|             count = 0 | ||||
|             for join in join_list: | ||||
|                 count += len(join) | ||||
|                 for alias in join: | ||||
|                     self.promote_alias(alias) | ||||
|             for alias in join_list: | ||||
|                 self.promote_alias(alias) | ||||
|             if not merged: | ||||
|                 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] | ||||
|                 entry = Node([(alias, j_col, None, 'isnull', True)]) | ||||
|                 entry.negate() | ||||
| @@ -989,10 +983,10 @@ class Query(object): | ||||
|         column (used for any 'where' constraint), the final 'opts' value and the | ||||
|         list of tables joined. | ||||
|         """ | ||||
|         joins = [[alias]] | ||||
|         used = set() | ||||
|         joins = [alias] | ||||
|         last = [0] | ||||
|         for pos, name in enumerate(names): | ||||
|             used.update(joins[-1]) | ||||
|             last.append(len(joins)) | ||||
|             if name == 'pk': | ||||
|                 name = opts.pk.name | ||||
|  | ||||
| @@ -1011,9 +1005,8 @@ class Query(object): | ||||
|                     raise FieldError("Cannot resolve keyword %r into field. " | ||||
|                             "Choices are: %s" % (name, ", ".join(names))) | ||||
|             if not allow_many and (m2m or not direct): | ||||
|                 for join in joins: | ||||
|                     for alias in join: | ||||
|                         self.unref_alias(alias) | ||||
|                 for alias in joins: | ||||
|                     self.unref_alias(alias) | ||||
|                 raise JoinError(pos + 1) | ||||
|             if model: | ||||
|                 # The field lives on a base class of the current model. | ||||
| @@ -1022,9 +1015,8 @@ class Query(object): | ||||
|                     lhs_col = opts.parents[int_model].column | ||||
|                     opts = int_model._meta | ||||
|                     alias = self.join((alias, opts.db_table, lhs_col, | ||||
|                             opts.pk.column), exclusions=used) | ||||
|                     alias_list.append(alias) | ||||
|                 joins.append(alias_list) | ||||
|                             opts.pk.column), exclusions=joins) | ||||
|                     joins.append(alias) | ||||
|             cached_data = opts._join_cache.get(name) | ||||
|             orig_opts = opts | ||||
|  | ||||
| @@ -1048,10 +1040,10 @@ class Query(object): | ||||
|                                 target) | ||||
|  | ||||
|                     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), | ||||
|                             dupe_multis, used, nullable=True) | ||||
|                     joins.append([int_alias, alias]) | ||||
|                             dupe_multis, joins, nullable=True) | ||||
|                     joins.extend([int_alias, alias]) | ||||
|                 elif field.rel: | ||||
|                     # One-to-one or many-to-one field | ||||
|                     if cached_data: | ||||
| @@ -1066,8 +1058,8 @@ class Query(object): | ||||
|                                 opts, target) | ||||
|  | ||||
|                     alias = self.join((alias, table, from_col, to_col), | ||||
|                             exclusions=used, nullable=field.null) | ||||
|                     joins.append([alias]) | ||||
|                             exclusions=joins, nullable=field.null) | ||||
|                     joins.append(alias) | ||||
|                 else: | ||||
|                     # Non-relation fields. | ||||
|                     target = field | ||||
| @@ -1094,10 +1086,10 @@ class Query(object): | ||||
|                                 target) | ||||
|  | ||||
|                     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), | ||||
|                             dupe_multis, used, nullable=True) | ||||
|                     joins.append([int_alias, alias]) | ||||
|                             dupe_multis, joins, nullable=True) | ||||
|                     joins.extend([int_alias, alias]) | ||||
|                 else: | ||||
|                     # One-to-many field (ForeignKey defined on the target model) | ||||
|                     if cached_data: | ||||
| @@ -1114,13 +1106,13 @@ class Query(object): | ||||
|                                 opts, target) | ||||
|  | ||||
|                     alias = self.join((alias, table, from_col, to_col), | ||||
|                             dupe_multis, used, nullable=True) | ||||
|                     joins.append([alias]) | ||||
|                             dupe_multis, joins, nullable=True) | ||||
|                     joins.append(alias) | ||||
|  | ||||
|         if pos != len(names) - 1: | ||||
|             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): | ||||
|         """ | ||||
| @@ -1179,9 +1171,10 @@ class Query(object): | ||||
|         opts = self.get_meta() | ||||
|         try: | ||||
|             for name in field_names: | ||||
|                 u1, target, u2, joins = self.setup_joins(name.split(LOOKUP_SEP), | ||||
|                         opts, alias, False, allow_m2m, True) | ||||
|                 self.select.append((joins[-1][-1], target.column)) | ||||
|                 u1, target, u2, joins, u3 = self.setup_joins( | ||||
|                         name.split(LOOKUP_SEP), opts, alias, False, allow_m2m, | ||||
|                         True) | ||||
|                 self.select.append((joins[-1], target.column)) | ||||
|         except JoinError: | ||||
|             raise FieldError("Invalid field name: '%s'" % name) | ||||
|  | ||||
| @@ -1294,20 +1287,18 @@ class Query(object): | ||||
|         """ | ||||
|         opts = self.model._meta | ||||
|         alias = self.get_initial_alias() | ||||
|         field, col, opts, joins = self.setup_joins(start.split(LOOKUP_SEP), | ||||
|                 opts, alias, False) | ||||
|         alias = joins[-1][0] | ||||
|         field, col, opts, joins, last = self.setup_joins( | ||||
|                 start.split(LOOKUP_SEP), opts, alias, False) | ||||
|         alias = joins[last[-1]] | ||||
|         self.select = [(alias, self.alias_map[alias][RHS_JOIN_COL])] | ||||
|         self.start_meta = opts | ||||
|  | ||||
|         # The call to setup_joins add an extra reference to everything in | ||||
|         # joins. So we need to unref everything once, and everything prior to | ||||
|         # the final join a second time. | ||||
|         for join in joins[:-1]: | ||||
|             for alias in join: | ||||
|                 self.unref_alias(alias) | ||||
|                 self.unref_alias(alias) | ||||
|         for alias in joins[-1]: | ||||
|         for alias in joins: | ||||
|             self.unref_alias(alias) | ||||
|         for alias in joins[:last[-1]]: | ||||
|             self.unref_alias(alias) | ||||
|  | ||||
|     def execute_sql(self, result_type=MULTI): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user