Django

Code

Changeset 7253

Show
Ignore:
Timestamp:
03/16/08 11:18:39 (8 months ago)
Author:
mtredinnick
Message:

queryset-refactor: More whack-a-mole optimisation work. Still got a couple of big spots to go, though.

Files:

Legend:

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

    r7152 r7253  
    161161        # can implement db_type() instead of get_internal_type() to specify 
    162162        # exactly which wacky database column type you want to use. 
    163         data_types = get_creation_module().DATA_TYPES 
    164         internal_type = self.get_internal_type() 
    165         if internal_type not in data_types
     163        try: 
     164            return get_creation_module().DATA_TYPES[self.get_internal_type()] % self.__dict__ 
     165        except KeyError
    166166            return None 
    167         return data_types[internal_type] % self.__dict__ 
    168167 
    169168    def validate_full(self, field_data, all_data): 
  • django/branches/queryset-refactor/django/db/models/options.py

    r7143 r7253  
    124124            if hasattr(self, '_field_cache'): 
    125125                del self._field_cache 
     126                del self._field_name_cache 
    126127 
    127128        if hasattr(self, '_name_map'): 
     
    156157        The getter for self.fields. This returns the list of field objects 
    157158        available to this model (including through parent models). 
    158         """ 
    159         try: 
    160             self._field_cache 
     159 
     160        Callers are not permitted to modify this list, since it's a reference 
     161        to this instance (not a copy). 
     162        """ 
     163        try: 
     164            self._field_name_cache 
    161165        except AttributeError: 
    162166            self._fill_fields_cache() 
    163         return self._field_cache.keys() 
     167        return self._field_name_cache 
    164168    fields = property(_fields) 
    165169 
    166170    def get_fields_with_model(self): 
    167171        """ 
    168         Returns a list of (field, model) pairs for all fields. The "model" 
     172        Returns a sequence of (field, model) pairs for all fields. The "model" 
    169173        element is None for fields on the current model. Mostly of use when 
    170174        constructing queries so that we know which model a field belongs to. 
     
    174178        except AttributeError: 
    175179            self._fill_fields_cache() 
    176         return self._field_cache.items() 
     180        return self._field_cache 
    177181 
    178182    def _fill_fields_cache(self): 
    179         cache = SortedDict() 
     183        cache = [] 
    180184        for parent in self.parents: 
    181185            for field, model in parent._meta.get_fields_with_model(): 
    182186                if model: 
    183                     cache[field] = model 
     187                    cache.append((field, model)) 
    184188                else: 
    185                     cache[field] = parent 
    186         for field in self.local_fields: 
    187             cache[field] = None 
    188         self._field_cache = cache 
     189                    cache.append((field, parent)) 
     190        cache.extend([(f, None) for f in self.local_fields]) 
     191        self._field_cache = tuple(cache) 
     192        self._field_name_cache = [x for x, _ in cache] 
    189193 
    190194    def _many_to_many(self): 
  • django/branches/queryset-refactor/django/db/models/query.py

    r7250 r7253  
    3232 
    3333    def __len__(self): 
    34         # Since __len__ is called quite frequently (as part of list(qs), which 
    35         # means as part of qs.get(), for example), we make some effort here to 
    36         # be as efficient as possible whilst not messing up any existing 
    37         # iterators against the queryset. 
     34        # Since __len__ is called quite frequently (for example, as part of 
     35        # list(qs), we make some effort here to be as efficient as possible 
     36        # whilst not messing up any existing iterators against the queryset. 
    3837        if self._result_cache is None: 
    3938            if self._iter: 
     
    5150        if self._iter: 
    5251            return self._result_iter() 
     52        # Python's list iterator is better than our version when we're just 
     53        # iterating over the cache. 
    5354        return iter(self._result_cache) 
    5455 
  • django/branches/queryset-refactor/django/db/models/sql/query.py

    r7247 r7253  
    88""" 
    99 
     10import itertools 
    1011from copy import deepcopy 
    1112 
     
    224225        if where: 
    225226            result.append('WHERE %s' % where) 
     227            params.extend(w_params) 
    226228        if self.extra_where: 
    227229            if not where: 
     
    230232                result.append('AND') 
    231233            result.append(' AND'.join(self.extra_where)) 
    232         params.extend(w_params) 
    233234 
    234235        if self.group_by: 
     
    362363                        aliases.append(col.alias) 
    363364        elif self.default_cols: 
    364             result = self.get_default_columns(lambda x, y: "%s.%s" % (qn(x), qn(y))
     365            result = self.get_default_columns(True
    365366            aliases = result[:] 
    366367 
     
    369370        aliases.extend(self.extra_select.keys()) 
    370371 
    371         self._select_aliases = dict.fromkeys(aliases) 
     372        self._select_aliases = set(aliases) 
    372373        return result 
    373374 
    374     def get_default_columns(self, combine_func=None): 
     375    def get_default_columns(self, as_str=False): 
    375376        """ 
    376377        Computes the default columns for selecting every field in the base 
    377378        model. Returns a list of default (alias, column) pairs suitable for 
    378         direct inclusion as the select columns. The 'combine_func' can be 
    379         passed in to change the returned data set to a list of some other 
    380         structure. 
    381         """ 
    382         # Note: We allow 'combine_func' here because this method is called a 
    383         # lot. The extra overhead from returning a list and then transforming 
    384         # it in get_columns() hurt performance in a measurable way. 
     379        inclusion as the select columns. If 'as_str' is True, returns a list of 
     380        strings, quoted appropriately for use in SQL directly. 
     381        """ 
    385382        result = [] 
    386383        table_alias = self.tables[0] 
    387384        root_pk = self.model._meta.pk.column 
    388385        seen = {None: table_alias} 
     386        qn = self.quote_name_unless_alias 
     387        qn2 = self.connection.ops.quote_name 
    389388        for field, model in self.model._meta.get_fields_with_model(): 
    390             if model not in seen: 
    391                 seen[model] = self.join((table_alias, model._meta.db_table, 
     389            try: 
     390                alias = seen[model] 
     391            except KeyError: 
     392                alias = self.join((table_alias, model._meta.db_table, 
    392393                        root_pk, model._meta.pk.column)) 
    393             if combine_func: 
    394                 result.append(combine_func(seen[model], field.column)) 
    395             else: 
    396                 result.append((seen[model], field.column)) 
     394                seen[model] = alias 
     395            if as_str: 
     396                result.append('%s.%s' % (qn(alias), qn2(field.column))) 
     397            else: 
     398                result.append((alias, field.column)) 
    397399        return result 
    398400 
     
    898900            # make the new additions (and any existing ones not used in the new 
    899901            # join list) an outer join. 
    900             join_it = nested_iter(join_list) 
     902            join_it = itertools.chain(*join_list) 
    901903            table_it = iter(self.tables) 
    902904            join_it.next(), table_it.next() 
     
    13261328        except EmptyResultSet: 
    13271329            if result_type == MULTI: 
    1328                 raise StopIteration 
     1330                return empty_iter() 
    13291331            else: 
    13301332                return 
     
    13331335        cursor.execute(sql, params) 
    13341336 
    1335         if result_type is None: 
     1337        if not result_type: 
    13361338            return cursor 
    1337  
    13381339        if result_type == SINGLE: 
    13391340            return cursor.fetchone() 
    1340  
    13411341        # The MULTI case. 
    1342         return results_iter(cursor
     1342        return iter((lambda: cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)), []
    13431343 
    13441344def get_order_dir(field, default='ASC'): 
     
    13551355    return field, dirn[0] 
    13561356 
    1357 def results_iter(cursor): 
     1357def empty_iter(): 
    13581358    """ 
    1359     An iterator over the result set that returns a chunk of rows at a time
     1359    Returns an iterator containing no results
    13601360    """ 
    1361     while 1: 
    1362         rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 
    1363         if not rows: 
    1364             raise StopIteration 
    1365         yield rows 
    1366  
    1367 def nested_iter(nested): 
    1368     """ 
    1369     An iterator over a sequence of sequences. Each element is returned in turn. 
    1370     Only handles one level of nesting, since that's all we need here. 
    1371     """ 
    1372     for seq in nested: 
    1373         for elt in seq: 
    1374             yield elt 
     1361    yield iter([]).next() 
    13751362 
    13761363def setup_join_cache(sender): 
  • django/branches/queryset-refactor/django/db/models/sql/subqueries.py

    r7247 r7253  
    239239    def __init__(self, *args, **kwargs): 
    240240        super(InsertQuery, self).__init__(*args, **kwargs) 
    241         self._setup_query() 
    242  
    243     def _setup_query(self): 
    244         """ 
    245         Run on initialisation and after cloning. 
    246         """ 
    247241        self.columns = [] 
    248242        self.values = [] 
     243        self.params = () 
     244 
     245    def clone(self, klass=None, **kwargs): 
     246        extras = {'columns': self.columns[:], 'values': self.values[:], 
     247                'params': self.params} 
     248        return super(InsertQuery, self).clone(klass, extras) 
    249249 
    250250    def as_sql(self): 
    251         self.select_related = False 
    252         self.pre_sql_setup() 
    253         qn = self.quote_name_unless_alias 
    254         result = ['INSERT INTO %s' % qn(self.tables[0])] 
     251        # We don't need quote_name_unless_alias() here, since these are all 
     252        # going to be column names (so we can avoid the extra overhead). 
     253        qn = self.connection.ops.quote_name 
     254        result = ['INSERT INTO %s' % qn(self.model._meta.db_table)] 
    255255        result.append('(%s)' % ', '.join([qn(c) for c in self.columns])) 
    256         result.append('VALUES (') 
    257         params = [] 
    258         first = True 
    259         for value in self.values: 
    260             prefix = not first and ', ' or '' 
    261             if isinstance(value, RawValue): 
    262                 result.append('%s%s' % (prefix, value.value)) 
    263             else: 
    264                 result.append('%s%%s' % prefix) 
    265                 params.append(value) 
    266             first = False 
    267         result.append(')') 
    268         return ' '.join(result), tuple(params) 
     256        result.append('VALUES (%s)' % ', '.join(self.values)) 
     257        return ' '.join(result), self.params 
    269258 
    270259    def execute_sql(self, return_id=False): 
    271260        cursor = super(InsertQuery, self).execute_sql(None) 
    272261        if return_id: 
    273             return self.connection.ops.last_insert_id(cursor, self.tables[0], 
    274                     self.model._meta.pk.column) 
     262            return self.connection.ops.last_insert_id(cursor, 
     263                    self.model._meta.db_table, self.model._meta.pk.column) 
    275264 
    276265    def insert_values(self, insert_values, raw_values=False): 
     
    286275        func = lambda x: self.model._meta.get_field_by_name(x)[0].column 
    287276        # keys() and values() return items in the same order, providing the 
    288         # dictionary hasn't changed between calls. So these lines work as 
    289         # intended. 
     277        # dictionary hasn't changed between calls. So the dual iteration here 
     278        # works as intended. 
    290279        for name in insert_values: 
    291280            if name == 'pk': 
     
    293282            self.columns.append(func(name)) 
    294283        if raw_values: 
    295             self.values.extend([RawValue(v) for v in insert_values.values()]
     284            self.values.extend(insert_values.values()
    296285        else: 
    297             self.values.extend(insert_values.values()) 
     286            values = insert_values.values() 
     287            self.params += tuple(values) 
     288            self.values.extend(['%s'] * len(values)) 
    298289 
    299290class DateQuery(Query): 
  • django/branches/queryset-refactor/tests/modeltests/model_inheritance/models.py

    r7241 r7253  
    264264>>> len(db.connection.queries) 
    2652653 
     266>>> settings.DEBUG = False 
    266267 
    267268"""}