Django

Code

Changeset 7255

Show
Ignore:
Timestamp:
03/17/08 08:32:11 (8 months ago)
Author:
mtredinnick
Message:

queyrset-refactor: Some more speed-ups due to datastructure changes.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/queryset-refactor/django/db/models/fields/related.py

    r7244 r7255  
    2929    Adds a lookup on ``cls`` when a related field is defined using a string, 
    3030    i.e.:: 
    31      
     31 
    3232        class MyModel(Model): 
    3333            fk = ForeignKey("AnotherModel") 
    34              
     34 
    3535    This string can be: 
    36      
     36 
    3737        * RECURSIVE_RELATIONSHIP_CONSTANT (i.e. "self") to indicate a recursive 
    3838          relation. 
    39            
     39 
    4040        * The name of a model (i.e "AnotherModel") to indicate another model in 
    4141          the same app. 
    42            
     42 
    4343        * An app-label and model name (i.e. "someapp.AnotherModel") to indicate 
    4444          another model in a different app. 
    45            
     45 
    4646    If the other model hasn't yet been loaded -- almost a given if you're using 
    4747    lazy relationships -- then the relation won't be set up until the 
     
    5252        app_label = cls._meta.app_label 
    5353        model_name = cls.__name__ 
    54      
     54 
    5555    else: 
    5656        # Look for an "app.Model" relation 
     
    6161            app_label = cls._meta.app_label 
    6262            model_name = relation 
    63      
     63 
    6464    # Try to look up the related model, and if it's already loaded resolve the 
    6565    # string right away. If get_model returns None, it means that the related 
    66     # model isn't loaded yet, so we need to pend the relation until the class  
     66    # model isn't loaded yet, so we need to pend the relation until the class 
    6767    # is prepared. 
    6868    model = get_model(app_label, model_name, False) 
     
    7474        value = (cls, field) 
    7575        pending_lookups.setdefault(key, []).append(value) 
    76      
     76 
    7777def do_pending_lookups(sender): 
    7878    """ 
     
    531531        tied. 
    532532        """ 
    533         return self.to._meta.get_field_by_name(self.field_name, True)[0] 
     533        data = self.to._meta.get_field_by_name(self.field_name) 
     534        if not data[2]: 
     535            raise FieldDoesNotExist("No related field named '%s'" % 
     536                    self.field_name) 
     537        return data[0] 
    534538 
    535539class OneToOneRel(ManyToOneRel): 
  • django/branches/queryset-refactor/django/db/models/options.py

    r7253 r7255  
    232232        raise FieldDoesNotExist, '%s has no field named %r' % (self.object_name, name) 
    233233 
    234     def get_field_by_name(self, name, only_direct=False): 
     234    def get_field_by_name(self, name): 
    235235        """ 
    236236        Returns the (field_object, model, direct, m2m), where field_object is 
     
    242242        with it). 
    243243 
    244         If 'only_direct' is True, only forwards relations (and non-relations) 
    245         are considered in the result. 
    246  
    247244        Uses a cache internally, so after the first access, this is very fast. 
    248245        """ 
    249246        try: 
    250             result = self._name_map.get(name) 
    251         except AttributeError: 
    252             cache = self.init_name_map() 
    253             result = cache.get(name
    254  
    255         if not result or (only_direct and not result[2])
     247            try: 
     248                return self._name_map[name] 
     249            except AttributeError: 
     250                cache = self.init_name_map(
     251                return self._name_map[name] 
     252        except KeyError
    256253            raise FieldDoesNotExist('%s has no field named %r' 
    257254                    % (self.object_name, name)) 
    258         return result 
    259255 
    260256    def get_all_field_names(self): 
  • django/branches/queryset-refactor/django/db/models/sql/query.py

    r7253 r7255  
    4747        self.alias_map = {}     # Maps alias to join information 
    4848        self.table_map = {}     # Maps table names to list of aliases. 
    49         self.rev_join_map = {}  # Reverse of join_map. (FIXME: Update comment) 
     49        self.join_map = {} 
     50        self.rev_join_map = {}  # Reverse of join_map. 
    5051        self.quote_cache = {} 
    5152        self.default_cols = True 
     
    131132        obj.alias_map = self.alias_map.copy() 
    132133        obj.table_map = self.table_map.copy() 
     134        obj.join_map = self.join_map.copy() 
    133135        obj.rev_join_map = self.rev_join_map.copy() 
    134136        obj.quote_cache = {} 
     
    272274        # Work out how to relabel the rhs aliases, if necessary. 
    273275        change_map = {} 
    274         used = {} 
     276        used = set() 
    275277        conjunction = (connector == AND) 
    276278        first = True 
     
    282284            new_alias = self.join(rhs.rev_join_map[alias], 
    283285                    (conjunction and not first), used, promote, not conjunction) 
    284             used[new_alias] = None 
     286            used.add(new_alias) 
    285287            change_map[alias] = new_alias 
    286288            first = False 
     
    412414        result = [] 
    413415        qn = self.quote_name_unless_alias 
     416        qn2 = self.connection.ops.quote_name 
    414417        first = True 
    415418        for alias in self.tables: 
    416419            if not self.alias_refcount[alias]: 
    417420                continue 
    418             join = self.alias_map[alias] 
    419             if join: 
    420                 name, alias, join_type, lhs, lhs_col, col, nullable = join 
    421                 alias_str = (alias != name and ' AS %s' % alias or '') 
    422             else: 
    423                 join_type = None 
    424                 alias_str = '' 
    425                 name = alias 
     421            name, alias, join_type, lhs, lhs_col, col, nullable = self.alias_map[alias] 
     422            alias_str = (alias != name and ' AS %s' % alias or '') 
    426423            if join_type and not first: 
    427424                result.append('%s %s%s ON (%s.%s = %s.%s)' 
    428425                        % (join_type, qn(name), alias_str, qn(lhs), 
    429                            qn(lhs_col), qn(alias), qn(col))) 
     426                           qn2(lhs_col), qn(alias), qn2(col))) 
    430427            else: 
    431428                connector = not first and ', ' or '' 
     
    473470            ordering = self.order_by or self.model._meta.ordering 
    474471        qn = self.quote_name_unless_alias 
     472        qn2 = self.connection.ops.quote_name 
    475473        distinct = self.distinct 
    476474        select_aliases = self._select_aliases 
     
    493491                continue 
    494492            if '.' in field: 
    495                 # This came in through an extra(ordering=...) addition. Pass it 
    496                 # on verbatim, after mapping the table name to an alias, if 
    497                 # necessary. 
     493                # This came in through an extra(order_by=...) addition. Pass it 
     494                # on verbatim. 
    498495                col, order = get_order_dir(field, asc) 
    499496                table, col = col.split('.', 1) 
    500                 elt = '%s.%s' % (qn(self.table_alias(table)[0]), col) 
     497                elt = '%s.%s' % (qn(table), col) 
    501498                if not distinct or elt in select_aliases: 
    502499                    result.append('%s %s' % (elt, order)) 
     
    506503                for table, col, order in self.find_ordering_name(field, 
    507504                        self.model._meta, default_order=asc): 
    508                     elt = '%s.%s' % (qn(table), qn(col)) 
     505                    elt = '%s.%s' % (qn(table), qn2(col)) 
    509506                    if not distinct or elt in select_aliases: 
    510507                        result.append('%s %s' % (elt, order)) 
     
    528525            alias = self.get_initial_alias() 
    529526        try: 
    530             field, target, opts, joins = self.setup_joins(pieces, opts, alias, 
    531                     False, False) 
     527            field, target, opts, joins, last = self.setup_joins(pieces, opts, 
     528                    alias, False, False) 
    532529        except JoinError: 
    533530            raise FieldError("Cannot order by many-valued field: '%s'" % name) 
    534         alias = joins[-1][-1] 
     531        alias = joins[-1] 
    535532        col = target.column 
    536533 
     
    541538            if not already_seen: 
    542539                already_seen = set() 
    543             join_tuple = tuple([tuple(j) for j in joins]
     540            join_tuple = tuple(joins
    544541            if join_tuple in already_seen: 
    545542                raise FieldError('Infinite loop caused by ordering.') 
     
    571568        most recently created alias for the table (if one exists) is reused. 
    572569        """ 
    573         if not create and table_name in self.table_map: 
    574             alias = self.table_map[table_name][-1] 
     570        current = self.table_map.get(table_name) 
     571        if not create and current: 
     572            alias = current[0] 
    575573            self.alias_refcount[alias] += 1 
    576574            return alias, False 
    577575 
    578576        # Create a new alias for this table. 
    579         if table_name not in self.table_map: 
     577        if current: 
     578            alias = '%s%d' % (self.alias_prefix, len(self.alias_map) + 1) 
     579            current.append(alias) 
     580        else: 
    580581            # The first occurence of a table uses the table name directly. 
    581582            alias = table_name 
    582         else: 
    583             alias = '%s%d' % (self.alias_prefix, len(self.alias_map) + 1) 
     583            self.table_map[alias] = [alias] 
    584584        self.alias_refcount[alias] = 1 
    585         self.alias_map[alias] = None 
    586         self.table_map.setdefault(table_name, []).append(alias) 
     585        #self.alias_map[alias] = None 
    587586        self.tables.append(alias) 
    588587        return alias, True 
     
    630629            alias_data[RHS_ALIAS] = new_alias 
    631630 
    632             self.rev_join_map[new_alias] = self.rev_join_map[old_alias] 
     631            t = self.rev_join_map[old_alias] 
     632            self.join_map[t] = new_alias 
     633            self.rev_join_map[new_alias] = t 
    633634            del self.rev_join_map[old_alias] 
    634635            self.alias_refcount[new_alias] = self.alias_refcount[old_alias] 
     
    655656                self.alias_map[alias] = tuple(data) 
    656657 
    657  
    658658    def bump_prefix(self): 
    659659        """ 
     
    725725        """ 
    726726        lhs, table, lhs_col, col = connection 
    727         if lhs is None: 
    728             lhs_table = None 
    729             is_table = False 
    730         elif lhs not in self.alias_map: 
     727        if lhs in self.alias_map: 
     728            lhs_table = self.alias_map[lhs][TABLE_NAME] 
     729        else: 
    731730            lhs_table = lhs 
    732             is_table = True 
    733         else: 
    734             lhs_table = self.alias_map[lhs][TABLE_NAME] 
    735             is_table = False 
    736731        t_ident = (lhs_table, table, lhs_col, col) 
    737         if not always_create: 
    738             for alias, row in self.rev_join_map.items(): 
    739                 if t_ident == row and alias not in exclusions: 
    740                     self.ref_alias(alias) 
    741                     if promote: 
    742                         self.promote_alias(alias) 
    743                     return alias 
    744             # If we get to here (no non-excluded alias exists), we'll fall 
    745             # through to creating a new alias. 
     732        alias = self.join_map.get(t_ident) 
     733        if alias and not always_create and alias not in exclusions: 
     734            self.ref_alias(alias) 
     735            if promote: 
     736                self.promote_alias(alias) 
     737            return alias 
    746738 
    747739        # No reuse is possible, so we need a new alias. 
    748         assert not is_table, \ 
    749                 "Must pass in lhs alias when creating a new join." 
    750740        alias, _ = self.table_alias(table, True) 
    751741        if not lhs: 
     
    759749        join = (table, alias, join_type, lhs, lhs_col, col, nullable) 
    760750        self.alias_map[alias] = join 
     751        self.join_map[t_ident] = alias 
    761752        self.rev_join_map[alias] = t_ident 
    762753        return alias 
     
    856847 
    857848        try: 
    858             field, target, opts, join_list = self.setup_joins(parts, opts, 
     849            field, target, opts, join_list, last = self.setup_joins(parts, opts, 
    859850                    alias, (connector == AND), allow_many) 
    860851        except JoinError, e: 
    861852            self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level])) 
    862853            return 
     854        final = len(join_list) 
     855        penultimate = last.pop() 
     856        if penultimate == final: 
     857            penultimate = last.pop() 
    863858        if trim and len(join_list) > 1: 
    864             extra = join_list[-1] 
    865             join_list = join_list[:-1] 
     859            extra = join_list[penultimate:] 
     860            join_list = join_list[:penultimate] 
     861            final = penultimate 
     862            penultimate = last.pop() 
    866863            col = self.alias_map[extra[0]][LHS_JOIN_COL] 
    867864            for alias in extra: 
     
    869866        else: 
    870867            col = target.column 
    871         alias = join_list[-1][-1] 
    872  
    873         if join_list
     868        alias = join_list[-1] 
     869 
     870        if final > 1
    874871            # An optimization: if the final join is against the same column as 
    875872            # we are comparing against, we can go back one step in the join 
     
    881878                alias = join[LHS_ALIAS] 
    882879                col = join[LHS_JOIN_COL] 
    883                 if len(join_list[-1]) == 1: 
    884                     join_list = join_list[:-1] 
    885                 else: 
    886                     join_list[-1] = join_list[-1][:-1] 
     880                join_list = join_list[:-1] 
     881                final -= 1 
     882                if final == penultimate: 
     883                    penultimate = last.pop() 
    887884 
    888885        if (lookup_type == 'isnull' and value is True and not negate and 
    889                 (len(join_list) > 1 or len(join_list[0]) > 1)): 
     886                final > 1): 
    890887            # If the comparison is against NULL, we need to use a left outer 
    891888            # join when connecting to the previous model. We make that 
    892889            # adjustment here. We don't do this unless needed as it's less 
    893890            # efficient at the database level. 
    894             self.promote_alias(join_list[-1][0]) 
     891            self.promote_alias(join_list[penultimate]) 
    895892 
    896893        if connector == OR: 
     
    900897            # make the new additions (and any existing ones not used in the new 
    901898            # join list) an outer join. 
    902             join_it = itertools.chain(*join_list) 
     899            join_it = iter(join_list) 
    903900            table_it = iter(self.tables) 
    904901            join_it.next(), table_it.next() 
     
    932929 
    933930        if negate: 
    934             count = 0 
    935             for join in join_list: 
    936                 count += len(join) 
    937                 for alias in join: 
    938                     self.promote_alias(alias) 
     931            for alias in join_list: 
     932                self.promote_alias(alias) 
    939933            if not merged: 
    940934                self.where.negate() 
    941             if count > 1 and lookup_type != 'isnull': 
     935            if final > 1 and lookup_type != 'isnull': 
    942936                j_col = self.alias_map[alias][RHS_JOIN_COL] 
    943937                entry = Node([(alias, j_col, None, 'isnull', True)]) 
     
    990984        list of tables joined. 
    991985        """ 
    992         joins = [[alias]
    993         used = set() 
     986        joins = [alias
     987        last = [0] 
    994988        for pos, name in enumerate(names): 
    995             used.update(joins[-1]
     989            last.append(len(joins)
    996990            if name == 'pk': 
    997991                name = opts.pk.name 
     
    10121006                            "Choices are: %s" % (name, ", ".join(names))) 
    10131007            if not allow_many and (m2m or not direct): 
    1014                 for join in joins: 
    1015                     for alias in join: 
    1016                         self.unref_alias(alias) 
     1008                for alias in joins: 
     1009                    self.unref_alias(alias) 
    10171010                raise JoinError(pos + 1) 
    10181011            if model: 
     
    10231016                    opts = int_model._meta 
    10241017                    alias = self.join((alias, opts.db_table, lhs_col, 
    1025                             opts.pk.column), exclusions=used) 
    1026                     alias_list.append(alias) 
    1027                 joins.append(alias_list) 
     1018                            opts.pk.column), exclusions=joins) 
     1019                    joins.append(alias) 
    10281020            cached_data = opts._join_cache.get(name) 
    10291021            orig_opts = opts 
     
    10491041 
    10501042                    int_alias = self.join((alias, table1, from_col1, to_col1), 
    1051                             dupe_multis, used, nullable=True) 
     1043                            dupe_multis, joins, nullable=True) 
    10521044                    alias = self.join((int_alias, table2, from_col2, to_col2), 
    1053                             dupe_multis, used, nullable=True) 
    1054                     joins.append([int_alias, alias]) 
     1045                            dupe_multis, joins, nullable=True) 
     1046                    joins.extend([int_alias, alias]) 
    10551047                elif field.rel: 
    10561048                    # One-to-one or many-to-one field 
     
    10671059 
    10681060                    alias = self.join((alias, table, from_col, to_col), 
    1069                             exclusions=used, nullable=field.null) 
    1070                     joins.append([alias]
     1061                            exclusions=joins, nullable=field.null) 
     1062                    joins.append(alias
    10711063                else: 
    10721064                    # Non-relation fields. 
     
    10951087 
    10961088                    int_alias = self.join((alias, table1, from_col1, to_col1), 
    1097                             dupe_multis, used, nullable=True) 
     1089                            dupe_multis, joins, nullable=True) 
    10981090                    alias = self.join((int_alias, table2, from_col2, to_col2), 
    1099                             dupe_multis, used, nullable=True) 
    1100                     joins.append([int_alias, alias]) 
     1091                            dupe_multis, joins, nullable=True) 
     1092                    joins.extend([int_alias, alias]) 
    11011093                else: 
    11021094                    # One-to-many field (ForeignKey defined on the target model) 
     
    11151107 
    11161108                    alias = self.join((alias, table, from_col, to_col), 
    1117                             dupe_multis, used, nullable=True) 
    1118                     joins.append([alias]
     1109                            dupe_multis, joins, nullable=True) 
     1110                    joins.append(alias
    11191111 
    11201112        if pos != len(names) - 1: 
    11211113            raise FieldError("Join on field %r not permitted." % name) 
    11221114 
    1123         return field, target, opts, joins 
     1115        return field, target, opts, joins, last 
    11241116 
    11251117    def split_exclude(self, filter_expr, prefix): 
     
    11801172        try: 
    11811173            for name in field_names: 
    1182                 u1, target, u2, joins = self.setup_joins(name.split(LOOKUP_SEP), 
    1183                         opts, alias, False, allow_m2m, True) 
    1184                 self.select.append((joins[-1][-1], target.column)) 
     1174                u1, target, u2, joins, u3 = self.setup_joins( 
     1175                        name.split(LOOKUP_SEP), opts, alias, False, allow_m2m, 
     1176                        True) 
     1177                self.select.append((joins[-1], target.column)) 
    11851178        except JoinError: 
    11861179            raise FieldError("Invalid field name: '%s'" % name) 
     
    12951288        opts = self.model._meta 
    12961289        alias = self.get_initial_alias() 
    1297         field, col, opts, joins = self.setup_joins(start.split(LOOKUP_SEP), 
    1298                 opts, alias, False) 
    1299         alias = joins[-1][0
     1290        field, col, opts, joins, last = self.setup_joins( 
     1291                start.split(LOOKUP_SEP), opts, alias, False) 
     1292        alias = joins[last[-1]
    13001293        self.select = [(alias, self.alias_map[alias][RHS_JOIN_COL])] 
    13011294        self.start_meta = opts 
     
    13041297        # joins. So we need to unref everything once, and everything prior to 
    13051298        # the final join a second time. 
    1306         for join in joins[:-1]: 
    1307             for alias in join: 
    1308                 self.unref_alias(alias) 
    1309                 self.unref_alias(alias) 
    1310         for alias in joins[-1]: 
     1299        for alias in joins: 
     1300            self.unref_alias(alias) 
     1301        for alias in joins[:last[-1]]: 
    13111302            self.unref_alias(alias) 
    13121303