Django

Code

Changeset 7773

Show
Ignore:
Timestamp:
06/26/08 22:27:20 (3 months ago)
Author:
mtredinnick
Message:

Reorganised the internals of the Where node a bit to fix some copying problems.

We no longer store any reference to Django field instances or models in the
Where node. This should improve cloning speed, fix some pickling difficulties,
reduce memory usage and remove some infinite loop possibilities in odd cases.
Slightly backwards incompatible if you're writing custom filters. See the
BackwardsIncompatibleChanges wiki page for details.

Fixed #7128, #7204, #7506.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/db/models/sql/query.py

    r7761 r7773  
    88""" 
    99 
     10import datetime 
    1011from copy import deepcopy 
    1112 
     
    10491050                self.promote_alias(table) 
    10501051 
    1051         self.where.add((alias, col, field, lookup_type, value), connector) 
     1052        # To save memory and copying time, convert the value from the Python 
     1053        # object to the actual value used in the SQL query. 
     1054        if field: 
     1055            params = field.get_db_prep_lookup(lookup_type, value) 
     1056        else: 
     1057            params = Field().get_db_prep_lookup(lookup_type, value) 
     1058        if isinstance(value, datetime.datetime): 
     1059            annotation = datetime.datetime 
     1060        else: 
     1061            annotation = bool(value) 
     1062 
     1063        self.where.add((alias, col, field.db_type(), lookup_type, annotation, 
     1064            params), connector) 
    10521065 
    10531066        if negate: 
     
    10591072                        if self.alias_map[alias][JOIN_TYPE] == self.LOUTER: 
    10601073                            j_col = self.alias_map[alias][RHS_JOIN_COL] 
    1061                             entry = Node([(alias, j_col, None, 'isnull', True)]) 
     1074                            entry = Node([(alias, j_col, None, 'isnull', True, 
     1075                                    [True])]) 
    10621076                            entry.negate() 
    10631077                            self.where.add(entry, AND) 
     
    10671081                    # exclude the "foo__in=[]" case from this handling, because 
    10681082                    # it's short-circuited in the Where class. 
    1069                     entry = Node([(alias, col, field, 'isnull', True)]) 
     1083                    entry = Node([(alias, col, None, 'isnull', True, [True])]) 
    10701084                    entry.negate() 
    10711085                    self.where.add(entry, AND) 
  • django/trunk/django/db/models/sql/subqueries.py

    r7763 r7773  
    5050                    where = self.where_class() 
    5151                    where.add((None, related.field.m2m_reverse_name(), 
    52                             related.field, 'in'
     52                            related.field.db_type(), 'in', True
    5353                            pk_list[offset : offset+GET_ITERATOR_CHUNK_SIZE]), 
    5454                            AND) 
     
    6060                from django.contrib.contenttypes.models import ContentType 
    6161                field = f.rel.to._meta.get_field(f.content_type_field_name) 
    62                 w1.add((None, field.column, field, 'exact'
    63                         ContentType.objects.get_for_model(cls).id), AND) 
     62                w1.add((None, field.column, field.db_type(), 'exact', True
     63                        [ContentType.objects.get_for_model(cls).id]), AND) 
    6464            for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): 
    6565                where = self.where_class() 
    66                 where.add((None, f.m2m_column_name(), f, 'in'
     66                where.add((None, f.m2m_column_name(), f.db_type(), 'in', True
    6767                        pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), 
    6868                        AND) 
     
    8282            where = self.where_class() 
    8383            field = self.model._meta.pk 
    84             where.add((None, field.column, field, 'in'
     84            where.add((None, field.column, field.db_type(), 'in', True
    8585                    pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), AND) 
    8686            self.do_query(self.model._meta.db_table, where) 
     
    205205            self.where = self.where_class() 
    206206            f = self.model._meta.pk 
    207             self.where.add((None, f.column, f, 'in'
     207            self.where.add((None, f.column, f.db_type(), 'in', True
    208208                    pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), 
    209209                    AND) 
  • django/trunk/django/db/models/sql/where.py

    r7620 r7773  
    2222 
    2323    The children in this tree are usually either Q-like objects or lists of 
    24     [table_alias, field_name, field_class, lookup_type, value]. However, a 
    25     child could also be any class with as_sql() and relabel_aliases() methods. 
     24    [table_alias, field_name, db_type, lookup_type, value_annotation, 
     25    params]. However, a child could also be any class with as_sql() and 
     26    relabel_aliases() methods. 
    2627    """ 
    2728    default = AND 
     
    8990    def make_atom(self, child, qn): 
    9091        """ 
    91         Turn a tuple (table_alias, field_name, field_class, lookup_type, value) 
    92         into valid SQL. 
     92        Turn a tuple (table_alias, field_name, db_type, lookup_type, 
     93        value_annot, params) into valid SQL. 
    9394 
    9495        Returns the string for the SQL fragment and the parameters to use for 
    9596        it. 
    9697        """ 
    97         table_alias, name, field, lookup_type, value = child 
     98        table_alias, name, db_type, lookup_type, value_annot, params = child 
    9899        if table_alias: 
    99100            lhs = '%s.%s' % (qn(table_alias), qn(name)) 
    100101        else: 
    101102            lhs = qn(name) 
    102         db_type = field and field.db_type() or None 
     103        ##db_type = field and field.db_type() or None 
    103104        field_sql = connection.ops.field_cast_sql(db_type) % lhs 
    104105 
    105         if isinstance(value, datetime.datetime)
     106        if value_annot is datetime.datetime
    106107            cast_sql = connection.ops.datetime_cast_sql() 
    107108        else: 
    108109            cast_sql = '%s' 
    109110 
    110         if field: 
    111             params = field.get_db_prep_lookup(lookup_type, value) 
    112         else: 
    113             params = Field().get_db_prep_lookup(lookup_type, value) 
    114111        if isinstance(params, QueryWrapper): 
    115112            extra, params = params.data 
     
    124121 
    125122        if lookup_type == 'in': 
    126             if not value
     123            if not value_annot
    127124                raise EmptyResultSet 
    128125            if extra: 
    129126                return ('%s IN %s' % (field_sql, extra), params) 
    130             return ('%s IN (%s)' % (field_sql, ', '.join(['%s'] * len(value))), 
     127            return ('%s IN (%s)' % (field_sql, ', '.join(['%s'] * len(params))), 
    131128                    params) 
    132129        elif lookup_type in ('range', 'year'): 
     
    136133                    field_sql), params) 
    137134        elif lookup_type == 'isnull': 
    138             return ('%s IS %sNULL' % (field_sql, (not value and 'NOT ' or '')), 
    139                     params
     135            return ('%s IS %sNULL' % (field_sql, 
     136                (not value_annot and 'NOT ' or '')), ()
    140137        elif lookup_type == 'search': 
    141138            return (connection.ops.fulltext_search_sql(field_sql), params) 
  • django/trunk/tests/regressiontests/queries/models.py

    r7765 r7773  
    44 
    55import datetime 
     6import pickle 
    67 
    78from django.db import models 
     
    792793[] 
    793794 
     795Bug #7204, #7506 -- make sure querysets with related fields can be pickled. If 
     796this doesn't crash, it's a Good Thing. 
     797>>> out = pickle.dumps(Item.objects.all()) 
     798 
    794799"""} 
    795800