Django

Code

Ticket #7210: expr.2.diff

File expr.2.diff, 40.8 kB (added by Alex, 3 months ago)

Added 2 missing files.

  • a/django/contrib/sites/management.py

    old new  
    1313            print "Creating example.com Site object" 
    1414        s = Site(domain="example.com", name="example.com") 
    1515        s.save() 
    16     Site.objects.clear_cache() 
    1716 
    1817dispatcher.connect(create_default_site, sender=site_app, signal=signals.post_syncdb) 
  • a/django/contrib/sites/models.py

    old new  
    4444    def __unicode__(self): 
    4545        return self.domain 
    4646 
    47     def delete(self): 
    48         pk = self.pk 
    49         super(Site, self).delete() 
    50         try: 
    51             del(SITE_CACHE[pk]) 
    52         except KeyError: 
    53             pass 
    54          
    55  
    5647class RequestSite(object): 
    5748    """ 
    5849    A class that shares the primary interface of Site (i.e., it has 
  • /dev/null

    old new  
    1 """ 
    2 >>> # Make sure that get_current() does not return a deleted Site object. 
    3 >>> from django.contrib.sites.models import Site 
    4 >>> s = Site.objects.get_current() 
    5 >>> s 
    6 <Site: example.com> 
    7  
    8 >>> s.delete() 
    9 >>> Site.objects.get_current() 
    10 Traceback (most recent call last): 
    11 ... 
    12 DoesNotExist: Site matching query does not exist. 
    13 """ 
  • a/django/db/models/__init__.py

    old new  
    44from django.db import connection 
    55from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models 
    66from django.db.models.query import Q 
     7from django.db.models.sql.expressions import F 
    78from django.db.models.manager import Manager 
    89from django.db.models.base import Model, AdminOptions 
    910from django.db.models.fields import * 
  • a/django/db/models/base.py

    old new  
    1010from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError 
    1111from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist 
    1212from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField 
    13 from django.db.models.query import delete_objects, Q, CollectedObjects 
     13from django.db.models.query import delete_objects, Q 
    1414from django.db.models.options import Options, AdminOptions 
    1515from django.db import connection, transaction 
    1616from django.db.models import signals 
     
    368368                error_dict[f.name] = errors 
    369369        return error_dict 
    370370 
    371     def _collect_sub_objects(self, seen_objs, parent=None, nullable=False): 
     371    def _collect_sub_objects(self, seen_objs): 
    372372        """ 
    373373        Recursively populates seen_objs with all objects related to this object. 
    374         When done, seen_objs.items() will be in the format: 
    375             [(model_class, {pk_val: obj, pk_val: obj, ...})
    376              (model_class, {pk_val: obj, pk_val: obj, ...}),...] 
     374        When done, seen_objs will be in the format: 
     375            {model_class: {pk_val: obj, pk_val: obj, ...}
     376             model_class: {pk_val: obj, pk_val: obj, ...}, ...} 
    377377        """ 
    378378        pk_val = self._get_pk_val() 
    379         if seen_objs.add(self.__class__, pk_val, self, parent, nullable): 
     379        if pk_val in seen_objs.setdefault(self.__class__, {}): 
    380380            return 
     381        seen_objs[self.__class__][pk_val] = self 
    381382 
    382383        for related in self._meta.get_all_related_objects(): 
    383384            rel_opts_name = related.get_accessor_name() 
     
    387388                except ObjectDoesNotExist: 
    388389                    pass 
    389390                else: 
    390                     sub_obj._collect_sub_objects(seen_objs, self.__class__, related.field.null
     391                    sub_obj._collect_sub_objects(seen_objs
    391392            else: 
    392393                for sub_obj in getattr(self, rel_opts_name).all(): 
    393                     sub_obj._collect_sub_objects(seen_objs, self.__class__, related.field.null
     394                    sub_obj._collect_sub_objects(seen_objs
    394395 
    395396    def delete(self): 
    396397        assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) 
    397398 
    398399        # Find all the objects than need to be deleted 
    399         seen_objs = CollectedObjects() 
     400        seen_objs = SortedDict() 
    400401        self._collect_sub_objects(seen_objs) 
    401402 
    402403        # Actually delete the objects 
  • a/django/db/models/loading.py

    old new  
    22 
    33from django.conf import settings 
    44from django.core.exceptions import ImproperlyConfigured 
    5 from django.utils.datastructures import SortedDict 
    6  
    75import sys 
    86import os 
    97import threading 
     
    2018    # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531. 
    2119    __shared_state = dict( 
    2220        # Keys of app_store are the model modules for each application. 
    23         app_store = SortedDict()
     21        app_store = {}
    2422 
    2523        # Mapping of app_labels to a dictionary of model names to model code. 
    26         app_models = SortedDict()
     24        app_models = {}
    2725 
    2826        # Mapping of app_labels to errors raised when trying to import the app. 
    2927        app_errors = {}, 
     
    135133        """ 
    136134        self._populate() 
    137135        if app_mod: 
    138             return self.app_models.get(app_mod.__name__.split('.')[-2], SortedDict()).values() 
     136            return self.app_models.get(app_mod.__name__.split('.')[-2], {}).values() 
    139137        else: 
    140138            model_list = [] 
    141139            for app_entry in self.app_models.itervalues(): 
     
    151149        """ 
    152150        if seed_cache: 
    153151            self._populate() 
    154         return self.app_models.get(app_label, SortedDict()).get(model_name.lower()) 
     152        return self.app_models.get(app_label, {}).get(model_name.lower()) 
    155153 
    156154    def register_models(self, app_label, *models): 
    157155        """ 
     
    161159            # Store as 'name: model' pair in a dictionary 
    162160            # in the app_models dictionary 
    163161            model_name = model._meta.object_name.lower() 
    164             model_dict = self.app_models.setdefault(app_label, SortedDict()
     162            model_dict = self.app_models.setdefault(app_label, {}
    165163            if model_name in model_dict: 
    166164                # The same model may be imported via different paths (e.g. 
    167165                # appname.models and project.appname.models). We use the source 
  • a/django/db/models/query.py

    old new  
    1616# Pull into this namespace for backwards compatibility 
    1717EmptyResultSet = sql.EmptyResultSet 
    1818 
    19 class CyclicDependency(Exception): 
    20     pass 
    21  
    22 class CollectedObjects(object): 
    23     """ 
    24     A container that stores keys and lists of values along with 
    25     remembering the parent objects for all the keys. 
    26  
    27     This is used for the database object deletion routines so that we 
    28     can calculate the 'leaf' objects which should be deleted first. 
    29     """ 
    30  
    31     def __init__(self): 
    32         self.data = {} 
    33         self.children = {} 
    34  
    35     def add(self, model, pk, obj, parent_model, nullable=False): 
    36         """ 
    37         Adds an item. 
    38         model is the class of the object being added, 
    39         pk is the primary key, obj is the object itself,  
    40         parent_model is the model of the parent object 
    41         that this object was reached through, nullable should 
    42         be True if this relation is nullable. 
    43  
    44         If the item already existed in the structure, 
    45         returns true, otherwise false. 
    46         """ 
    47         d = self.data.setdefault(model, SortedDict()) 
    48         retval = pk in d 
    49         d[pk] = obj 
    50         # Nullable relationships can be ignored -- they 
    51         # are nulled out before deleting, and therefore 
    52         # do not affect the order in which objects have 
    53         # to be deleted. 
    54         if parent_model is not None and not nullable: 
    55             self.children.setdefault(parent_model, []).append(model) 
    56  
    57         return retval 
    58  
    59     def __contains__(self, key): 
    60         return self.data.__contains__(key) 
    61  
    62     def __getitem__(self, key): 
    63         return self.data[key] 
    64  
    65     def __nonzero__(self): 
    66         return bool(self.data) 
    67  
    68     def iteritems(self): 
    69         for k in self.ordered_keys(): 
    70             yield k, self[k] 
    71  
    72     def items(self): 
    73         return list(self.iteritems()) 
    74  
    75     def keys(self): 
    76         return self.ordered_keys() 
    77  
    78     def ordered_keys(self): 
    79         """ 
    80         Returns the models in the order that they should be  
    81         dealth with i.e. models with no dependencies first. 
    82         """ 
    83         dealt_with = SortedDict() 
    84         # Start with items that have no children 
    85         models = self.data.keys() 
    86         while len(dealt_with) < len(models): 
    87             found = False 
    88             for model in models: 
    89                 children = self.children.setdefault(model, []) 
    90                 if len([c for c in children if c not in dealt_with]) == 0: 
    91                     dealt_with[model] = None 
    92                     found = True 
    93             if not found: 
    94                 raise CyclicDependency("There is a cyclic dependency of items to be processed.") 
    95              
    96         return dealt_with.keys() 
    97  
    98     def unordered_keys(self): 
    99         """ 
    100         Fallback for the case where is a cyclic dependency but we 
    101         don't care. 
    102         """ 
    103         return self.data.keys() 
    104  
    10519class QuerySet(object): 
    10620    "Represents a lazy database lookup for a set of objects" 
    10721    def __init__(self, model=None, query=None): 
     
    361275        while 1: 
    362276            # Collect all the objects to be deleted in this chunk, and all the 
    363277            # objects that are related to the objects that are to be deleted. 
    364             seen_objs = CollectedObjects() 
     278            seen_objs = SortedDict() 
    365279            for object in del_query[:CHUNK_SIZE]: 
    366280                object._collect_sub_objects(seen_objs) 
    367281 
     
    768682    Iterate through a list of seen classes, and remove any instances that are 
    769683    referred to. 
    770684    """ 
    771     try: 
    772         ordered_classes = seen_objs.keys() 
    773     except CyclicDependency: 
    774         # if there is a cyclic dependency, we cannot in general delete 
    775         # the objects.  However, if an appropriate transaction is set 
    776         # up, or if the database is lax enough, it will succeed.  
    777         # So for now, we go ahead and try anway. 
    778         ordered_classes = seen_objs.unordered_keys() 
    779  
    780     obj_pairs = {} 
     685    ordered_classes = seen_objs.keys() 
     686    ordered_classes.reverse() 
     687 
    781688    for cls in ordered_classes: 
    782         items = seen_objs[cls].items() 
    783         items.sort() 
    784         obj_pairs[cls] = items 
     689        seen_objs[cls] = seen_objs[cls].items() 
     690        seen_objs[cls].sort() 
    785691 
    786692        # Pre notify all instances to be deleted 
    787         for pk_val, instance in items
     693        for pk_val, instance in seen_objs[cls]
    788694            dispatcher.send(signal=signals.pre_delete, sender=cls, 
    789695                    instance=instance) 
    790696 
    791         pk_list = [pk for pk,instance in items
     697        pk_list = [pk for pk,instance in seen_objs[cls]
    792698        del_query = sql.DeleteQuery(cls, connection) 
    793699        del_query.delete_batch_related(pk_list) 
    794700 
     
    799705 
    800706    # Now delete the actual data 
    801707    for cls in ordered_classes: 
    802         items = obj_pairs[cls] 
    803         items.reverse() 
    804  
    805         pk_list = [pk for pk,instance in items] 
     708        seen_objs[cls].reverse() 
     709        pk_list = [pk for pk,instance in seen_objs[cls]] 
    806710        del_query = sql.DeleteQuery(cls, connection) 
    807711        del_query.delete_batch(pk_list) 
    808712 
    809713        # Last cleanup; set NULLs where there once was a reference to the 
    810714        # object, NULL the primary key of the found objects, and perform 
    811715        # post-notification. 
    812         for pk_val, instance in items
     716        for pk_val, instance in seen_objs[cls]
    813717            for field in cls._meta.fields: 
    814718                if field.rel and field.null and field.rel.to in seen_objs: 
    815719                    setattr(instance, field.attname, None) 
  • /dev/null

    old new  
     1from copy import deepcopy 
     2from datetime import datetime 
     3 
     4from django.utils import tree 
     5from django.core.exceptions import FieldError 
     6from django.db import connection 
     7from django.db.models.fields import Field, FieldDoesNotExist 
     8from django.db.models.query_utils import QueryWrapper 
     9 
     10class Expression(object): 
     11    """ 
     12    Base class for all sql expressions, expected by QuerySet.update. 
     13    """ 
     14    # Arithmetic connection types 
     15    ADD = '+' 
     16    SUB = '-' 
     17    MUL = '*' 
     18    DIV = '/' 
     19    MOD = '%%' 
     20 
     21    # Bitwise connection types 
     22    AND = '&' 
     23    OR = '|' 
     24 
     25    def _combine(self, other, conn, reversed, node=None): 
     26        if reversed: 
     27            obj = ExpressionNode([Literal(other)], conn) 
     28            obj.add(node or self, conn) 
     29        else: 
     30            obj = node or ExpressionNode([self], conn) 
     31            if isinstance(other, Expression): 
     32                obj.add(other, conn) 
     33            else: 
     34                obj.add(Literal(other), conn) 
     35        return obj 
     36 
     37    def __add__(self, other): 
     38        return self._combine(other, self.ADD, False) 
     39 
     40    def __sub__(self, other): 
     41        return self._combine(other, self.SUB, False) 
     42 
     43    def __mul__(self, other): 
     44        return self._combine(other, self.MUL, False) 
     45 
     46    def __div__(self, other): 
     47        return self._combine(other, self.DIV, False) 
     48 
     49    def __mod__(self, other): 
     50        return self._combine(other, self.MOD, False) 
     51 
     52    def __and__(self, other): 
     53        return self._combine(other, self.AND, False) 
     54 
     55    def __or__(self, other): 
     56        return self._combine(other, self.OR, False) 
     57 
     58    def __radd__(self, other): 
     59        return self._combine(other, self.ADD, True) 
     60 
     61    def __rsub__(self, other): 
     62        return self._combine(other, self.SUB, True) 
     63 
     64    def __rmul__(self, other): 
     65        return self._combine(other, self.MUL, True) 
     66 
     67    def __rdiv__(self, other): 
     68        return self._combine(other, self.DIV, True) 
     69 
     70    def __rmod__(self, other): 
     71        return self._combine(other, self.MOD, True) 
     72 
     73    def __rand__(self, other): 
     74        return self._combine(other, self.AND, True) 
     75 
     76    def __ror__(self, other): 
     77        return self._combine(other, self.OR, True) 
     78 
     79    def as_sql(self, opts, field, prep_func=None, qn=None): 
     80        raise NotImplementedError 
     81 
     82class ExpressionNode(Expression, tree.Node): 
     83    default = None 
     84 
     85    def __init__(self, children=None, connector=None, negated=False): 
     86        if children is not None and len(children) > 1 and connector is None: 
     87            raise TypeError('You have to specify a connector.') 
     88        super(ExpressionNode, self).__init__(children, connector, negated) 
     89 
     90    def _combine(self, *args, **kwargs): 
     91        return super(ExpressionNode, self)._combine(node=deepcopy(self), *args, **kwargs) 
     92 
     93    def as_sql(self, opts, field, prep_func=None, qn=None, node=None): 
     94        if not qn: 
     95            qn = connection.ops.quote_name 
     96        if node is None: 
     97            node = self 
     98 
     99        result = [] 
     100        result_params = [] 
     101        for child in node.children: 
     102            if hasattr(child, 'as_sql'): 
     103                sql, params = child.as_sql(opts, field, prep_func, qn) 
     104                format = '%s' 
     105            else: 
     106                sql, params = self.as_sql(opts, field, prep_func, qn, child) 
     107                if len(child.children) > 1: 
     108                    format = '(%s)' 
     109                else: 
     110                    format = '%s' 
     111            if sql: 
     112                result.append(format % sql) 
     113                result_params.extend(params) 
     114        conn = ' %s ' % node.connector 
     115        return conn.join(result), result_params 
     116 
     117class Literal(Expression): 
     118    """ 
     119    An expression representing the given value. 
     120    """ 
     121    def __init__(self, value): 
     122        self.value = value 
     123 
     124    def as_sql(self, opts, field, prep_func=None, qn=None): 
     125        if self.value is None: 
     126            return 'NULL', () 
     127 
     128        if isinstance(self.value, datetime): 
     129            sql = connection.ops.datetime_cast_sql() 
     130        else: 
     131            sql = '%s' 
     132        params = prep_func and prep_func(self.value) or (self.value,) 
     133 
     134        if isinstance(params, QueryWrapper): 
     135            return params.data 
     136        return sql, params 
     137 
     138class F(Expression): 
     139    """ 
     140    An expression representing the value of the given field. 
     141    """ 
     142    def __init__(self, name): 
     143        self.name = name 
     144 
     145    def as_sql(self, opts, field, prep_func=None, qn=None): 
     146        if not qn: 
     147            qn = connection.ops.quote_name 
     148 
     149        try: 
     150            src_field = opts.get_field(self.name) 
     151        except FieldDoesNotExist: 
     152            names = opts.get_all_field_names() 
     153            raise FieldError('Cannot resolve keyword %r into field. ' 
     154                    'Choices are: %s' % (self.name, ', '.join(names))) 
     155 
     156        field_sql = connection.ops.field_cast_sql(src_field.db_type()) 
     157        lhs = '%s.%s' % (qn(opts.db_table), qn(src_field.column)) 
     158        return field_sql % lhs, () 
  • a/django/db/models/sql/query.py

    old new  
    250250        # get_from_clause() for details. 
    251251        from_, f_params = self.get_from_clause() 
    252252 
    253         where, w_params = self.where.as_sql(qn=self.quote_name_unless_alias) 
     253        where, w_params = self.where.as_sql(self.get_meta(), qn=self.quote_name_unless_alias) 
    254254        params = list(self.extra_select_params) 
    255255 
    256256        result = ['SELECT'] 
  • a/django/db/models/sql/subqueries.py

    old new  
    77from django.db.models.sql.datastructures import Date 
    88from django.db.models.sql.query import Query 
    99from django.db.models.sql.where import AND 
     10from django.db.models.sql.expressions import Expression, Literal 
    1011 
    1112__all__ = ['DeleteQuery', 'UpdateQuery', 'InsertQuery', 'DateQuery', 
    1213        'CountQuery'] 
     
    2425        assert len(self.tables) == 1, \ 
    2526                "Can only delete from one table at a time." 
    2627        result = ['DELETE FROM %s' % self.quote_name_unless_alias(self.tables[0])] 
    27         where, params = self.where.as_sql(
     28        where, params = self.where.as_sql(self.get_meta()
    2829        result.append('WHERE %s' % where) 
    2930        return ' '.join(result), tuple(params) 
    3031 
     
    126127        result = ['UPDATE %s' % qn(table)] 
    127128        result.append('SET') 
    128129        values, update_params = [], [] 
    129         for name, val, placeholder in self.values: 
    130             if val is not None: 
    131                 values.append('%s = %s' % (qn(name), placeholder)) 
    132                 update_params.append(val) 
    133             else: 
    134                 values.append('%s = NULL' % qn(name)) 
     130        for name, sql, params in self.values: 
     131            values.append('%s = %s' % (qn(name), sql)) 
     132            update_params.extend(params) 
    135133        result.append(', '.join(values)) 
    136         where, params = self.where.as_sql(
     134        where, params = self.where.as_sql(self.get_meta()
    137135        if where: 
    138136            result.append('WHERE %s' % where) 
    139137        return ' '.join(result), tuple(update_params + params) 
     
    207205            self.where.add((None, f.column, f, 'in', 
    208206                    pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), 
    209207                    AND) 
    210             self.values = [(related_field.column, None, '%s')] 
     208            self.values = [(related_field.column, 'NULL', ())] 
    211209            self.execute_sql(None) 
    212210 
    213211    def add_update_values(self, values): 
     
    232230        """ 
    233231        from django.db.models.base import Model 
    234232        for field, model, val in values_seq: 
    235             # FIXME: Some sort of db_prep_* is probably more appropriate here. 
    236             if field.rel and isinstance(val, Model): 
    237                 val = val.pk 
    238  
    239             # Getting the placeholder for the field. 
    240             if hasattr(field, 'get_placeholder'): 
    241                 placeholder = field.get_placeholder(val) 
     233            if isinstance(val, Expression): 
     234                expr = val 
    242235            else: 
    243                 placeholder = '%s' 
     236                expr = Literal(val) 
     237 
     238            sql, params = expr.as_sql( 
     239                self.get_meta(), 
     240                field, 
     241                lambda x: field.get_db_prep_lookup('exact', field.get_db_prep_save(x)), 
     242                self.connection.ops.quote_name) 
    244243 
    245244            if model: 
    246                 self.add_related_update(model, field.column, val, placeholder
     245                self.add_related_update(model, field.column, sql, params
    247246            else: 
    248                 self.values.append((field.column, val, placeholder)) 
     247                self.values.append((field.column, sql, params)) 
    249248 
    250     def add_related_update(self, model, column, value, placeholder): 
     249    def add_related_update(self, model, column, sql, params): 
    251250        """ 
    252251        Adds (name, value) to an update query for an ancestor model. 
    253252 
    254253        Updates are coalesced so that we only run one update query per ancestor. 
    255254        """ 
    256255        try: 
    257             self.related_updates[model].append((column, value, placeholder)) 
     256            self.related_updates[model].append((column, sql, params)) 
    258257        except KeyError: 
    259             self.related_updates[model] = [(column, value, placeholder)] 
     258            self.related_updates[model] = [(column, sql, params)] 
    260259 
    261260    def get_related_updates(self): 
    262261        """ 
     
    312311        parameters. This provides a way to insert NULL and DEFAULT keywords 
    313312        into the query, for example. 
    314313        """ 
    315         placeholders, values = [], [] 
     314        values = [] 
    316315        for field, val in insert_values: 
    317             if hasattr(field, 'get_placeholder'): 
    318                 # Some fields (e.g. geo fields) need special munging before 
    319                 # they can be inserted. 
    320                 placeholders.append(field.get_placeholder(val)) 
    321             else: 
    322                 placeholders.append('%s') 
    323  
    324316            self.columns.append(field.column) 
    325317            values.append(val) 
    326318        if raw_values: 
    327319            self.values.extend(values) 
    328320        else: 
    329321            self.params += tuple(values) 
    330             self.values.extend(placeholders
     322            self.values.extend(['%s'] * len(values)
    331323 
    332324class DateQuery(Query): 
    333325    """ 
  • a/django/db/models/sql/where.py

    old new  
    44import datetime 
    55 
    66from django.utils import tree 
     7from django.utils.functional import curry 
    78from django.db import connection 
    89from django.db.models.fields import Field 
    910from django.db.models.query_utils import QueryWrapper 
     11from django.db.models.sql.expressions import Expression, Literal 
    1012from datastructures import EmptyResultSet, FullResultSet 
    1113 
    1214# Connection types 
     
    2628    """ 
    2729    default = AND 
    2830 
    29     def as_sql(self, node=None, qn=None): 
     31    def as_sql(self, opts, node=None, qn=None): 
    3032        """ 
    3133        Returns the SQL version of the where clause and the value to be 
    3234        substituted in. Returns None, None if this node is empty. 
     
    4749        for child in node.children: 
    4850            try: 
    4951                if hasattr(child, 'as_sql'): 
    50                     sql, params = child.as_sql(qn=qn) 
     52                    sql, params = child.as_sql(opts, qn=qn) 
    5153                    format = '(%s)' 
    5254                elif isinstance(child, tree.Node): 
    53                     sql, params = self.as_sql(child, qn) 
     55                    sql, params = self.as_sql(opts, child, qn) 
    5456                    if child.negated: 
    5557                        format = 'NOT (%s)' 
    5658                    elif len(child.children) == 1: 
     
    5860                    else: 
    5961                        format = '(%s)' 
    6062                else: 
    61                     sql, params = self.make_atom(child, qn) 
     63                    sql, params = self.make_atom(opts, child, qn) 
    6264                    format = '%s' 
    6365            except EmptyResultSet: 
    6466                if node.connector == AND and not node.negated: 
     
    8688        conn = ' %s ' % node.connector 
    8789        return conn.join(result), result_params 
    8890 
    89     def make_atom(self, child, qn): 
     91    def make_atom(self, opts, child, qn): 
    9092        """ 
    9193        Turn a tuple (table_alias, field_name, field_class, lookup_type, value) 
    9294        into valid SQL. 
     
    99101            lhs = '%s.%s' % (qn(table_alias), qn(name)) 
    100102        else: 
    101103            lhs = qn(name) 
     104        if not field: 
     105            field = Field() 
    102106        db_type = field and field.db_type() or None 
    103107        field_sql = connection.ops.field_cast_sql(db_type) % lhs 
     108        prep_func = curry(field.get_db_prep_lookup, lookup_type) 
    104109 
    105         if isinstance(value, datetime.datetime): 
    106             cast_sql = connection.ops.datetime_cast_sql() 
    107         else: 
    108             cast_sql = '%s' 
     110        if lookup_type in connection.operators: 
     111            if isinstance(value, Expression): 
     112                sql, params = value.as_sql(opts, field, prep_func, qn) 
     113            else: 
     114                sql, params = Literal(value).as_sql(opts, field, prep_func, qn) 
    109115 
    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) 
     116            format = '%s %s' % ( 
     117                connection.ops.lookup_cast(lookup_type), 
     118                connection.operators[lookup_type]) 
     119            return format % (field_sql, sql), params 
     120 
     121        if isinstance(value, Expression): 
     122            raise TypeError('Invalid lookup_type for use with %s object: %r' % ( 
     123                value.__class__.__name__, lookup_type)) 
     124 
     125        params = prep_func(value) 
    114126        if isinstance(params, QueryWrapper): 
    115127            extra, params = params.data 
    116128        else: 
    117129            extra = '' 
    118130 
    119         if lookup_type in connection.operators: 
    120             format = "%s %%s %s" % (connection.ops.lookup_cast(lookup_type), 
    121                     extra) 
    122             return (format % (field_sql, 
    123                     connection.operators[lookup_type] % cast_sql), params) 
    124  
    125131        if lookup_type == 'in': 
    126132            if not value: 
    127133                raise EmptyResultSet 
    128134            if extra: 
    129135                return ('%s IN %s' % (field_sql, extra), params) 
    130             return ('%s IN (%s)' % (field_sql, ', '.join(['%s'] * len(value))), 
    131                     params) 
     136            return ('%s IN (%s)' % (field_sql, ', '.join(['%s'] * len(value))), params) 
    132137        elif lookup_type in ('range', 'year'): 
    133138            return ('%s BETWEEN %%s and %%s' % field_sql, params) 
    134139        elif lookup_type in ('month', 'day'): 
     
    164169    """ 
    165170    A node that matches everything. 
    166171    """ 
    167     def as_sql(self, qn=None): 
     172    def as_sql(self, opts, qn=None): 
    168173        raise FullResultSet 
    169174 
    170175    def relabel_aliases(self, change_map, node=None): 
  • /dev/null

    old new  
  • /dev/null

    old new  
    1 # coding: utf-8 
    2 """ 
    3 Tests for some corner cases with deleting. 
    4 """ 
    5  
    6 from django.db import models 
    7  
    8 class DefaultRepr(object): 
    9     def __repr__(self): 
    10         return u"<%s: %s>" % (self.__class__.__name__, self.__dict__) 
    11  
    12 class A(DefaultRepr, models.Model): 
    13     pass 
    14  
    15 class B(DefaultRepr, models.Model): 
    16     a = models.ForeignKey(A) 
    17  
    18 class C(DefaultRepr, models.Model): 
    19     b = models.ForeignKey(B) 
    20  
    21 class D(DefaultRepr, models.Model): 
    22     c = models.ForeignKey(C) 
    23     a = models.ForeignKey(A) 
    24  
    25 # Simplified, we have: 
    26 # A 
    27 # B -> A 
    28 # C -> B 
    29 # D -> C 
    30 # D -> A 
    31  
    32 # So, we must delete Ds first of all, then Cs then Bs then As. 
    33 # However, if we start at As, we might find Bs first (in which  
    34 # case things will be nice), or find Ds first. 
    35  
    36 # Some mutually dependent models, but nullable 
    37 class E(DefaultRepr, models.Model): 
    38     f = models.ForeignKey('F', null=True, related_name='e_rel') 
    39  
    40 class F(DefaultRepr, models.Model): 
    41     e = models.ForeignKey(E, related_name='f_rel') 
    42  
    43  
    44 __test__ = {'API_TESTS': """ 
    45 # First, some tests for the datastructure we use 
    46  
    47 >>> from django.db.models.query import CollectedObjects 
    48  
    49 >>> g = CollectedObjects() 
    50 >>> g.add("key1", 1, "item1", None) 
    51 False 
    52 >>> g["key1"] 
    53 {1: 'item1'} 
    54 >>> g.add("key2", 1, "item1", "key1") 
    55 False 
    56 >>> g.add("key2", 2, "item2", "key1") 
    57 False 
    58 >>> g["key2"] 
    59 {1: 'item1', 2: 'item2'} 
    60 >>> g.add("key3", 1, "item1", "key1") 
    61 False 
    62 >>> g.add("key3", 1, "item1", "key2") 
    63 True 
    64 >>> g.ordered_keys() 
    65 ['key3', 'key2', 'key1'] 
    66  
    67 >>> g.add("key2", 1, "item1", "key3") 
    68 True 
    69 >>> g.ordered_keys() 
    70 Traceback (most recent call last): 
    71     ... 
    72 CyclicDependency: There is a cyclic dependency of items to be processed. 
    73  
    74  
    75  
    76 # Due to the way that transactions work in the test harness, 
    77 # doing m.delete() here can work but fail in a real situation, 
    78 # since it may delete all objects, but not in the right order. 
    79 # So we manually check that the order of deletion is correct. 
    80  
    81 # Also, it is possible that the order is correct 'accidentally', due 
    82 # solely to order of imports etc.  To check this, we set the order 
    83 # that 'get_models()' will retrieve to a known 'nice' order, and 
    84 # then try again with a known 'tricky' order.  Slightly naughty 
    85 # access to internals here :-) 
    86  
    87 >>> from django.db.models.loading import cache 
    88  
    89 # Nice order 
    90 >>> cache.app_models['delete'].keyOrder = ['a', 'b', 'c', 'd'] 
    91 >>> del A._meta._related_objects_cache 
    92 >>> del B._meta._related_objects_cache 
    93 >>> del C._meta._related_objects_cache 
    94 >>> del D._meta._related_objects_cache 
    95  
    96 >>> a1 = A() 
    97 >>> a1.save() 
    98 >>> b1 = B(a=a1) 
    99 >>> b1.save() 
    100 >>> c1 = C(b=b1) 
    101 >>> c1.save() 
    102 >>> d1 = D(c=c1, a=a1) 
    103 >>> d1.save() 
    104  
    105 >>> o = CollectedObjects() 
    106 >>> a1._collect_sub_objects(o) 
    107 >>> o.keys() 
    108 [<class 'modeltests.delete.models.D'>, <class 'modeltests.delete.models.C'>, <class 'modeltests.delete.models.B'>, <class 'modeltests.delete.models.A'>] 
    109 >>> a1.delete() 
    110  
    111 # Same again with a known bad order 
    112 >>> cache.app_models['delete'].keyOrder = ['d', 'c', 'b', 'a'] 
    113 >>> del A._meta._related_objects_cache 
    114 >>> del B._meta._related_objects_cache 
    115 >>> del C._meta._related_objects_cache 
    116 >>> del D._meta._related_objects_cache 
    117  
    118 >>> a2 = A() 
    119 >>> a2.save() 
    120 >>> b2 = B(a=a2) 
    121 >>> b2.save() 
    122 >>> c2 = C(b=b2) 
    123 >>> c2.save() 
    124 >>> d2 = D(c=c2, a=a2) 
    125 >>> d2.save() 
    126  
    127 >>> o = CollectedObjects() 
    128 >>> a2._collect_sub_objects(o) 
    129 >>> o.keys() 
    130 [<class 'modeltests.delete.models.D'>, <class 'modeltests.delete.models.C'>, <class 'modeltests.delete.models.B'>, <class 'modeltests.delete.models.A'>] 
    131 >>> a2.delete() 
    132  
    133 # Tests for nullable related fields 
    134  
    135 >>> g = CollectedObjects() 
    136 >>> g.add("key1", 1, "item1", None) 
    137 False 
    138 >>> g.add("key2", 1, "item1", "key1", nullable=True) 
    139 False 
    140 >>> g.add("key1", 1, "item1", "key2") 
    141 True 
    142 >>> g.ordered_keys() 
    143 ['key1', 'key2'] 
    144  
    145 >>> e1 = E() 
    146 >>> e1.save() 
    147 >>> f1 = F(e=e1) 
    148 >>> f1.save() 
    149 >>> e1.f = f1 
    150 >>> e1.save() 
    151  
    152 # Since E.f is nullable, we should delete F first (after nulling out 
    153 # the E.f field), then E. 
    154  
    155 >>> o = CollectedObjects() 
    156 >>> e1._collect_sub_objects(o) 
    157 >>> o.keys() 
    158 [<class 'modeltests.delete.models.F'>, <class 'modeltests.delete.models.E'>] 
    159  
    160 >>> e1.delete() 
    161  
    162 >>> e2 = E() 
    163 >>> e2.save() 
    164 >>> f2 = F(e=e2) 
    165 >>> f2.save() 
    166 >>> e2.f = f2 
    167 >>> e2.save() 
    168  
    169 # Same deal as before, though we are starting from the other object. 
    170  
    171 >>> o = CollectedObjects() 
    172 >>> f2._collect_sub_objects(o) 
    173 >>> o.keys() 
    174 [<class 'modeltests.delete.models.F'>, <class 'modeltests.delete.models.E'>] 
    175  
    176 >>> f2.delete() 
    177  
    178 """ 
    179 } 
  • /dev/null

    old new  
     1""" 
     2Tests for the update() queryset method that allows in-place, multi-object 
     3updates. 
     4""" 
     5 
     6from django.db import models 
     7 
     8# 
     9# Model for testing arithmetic expressions. 
     10# 
     11 
     12class Number(models.Model): 
     13    integer = models.IntegerField() 
     14    float = models.FloatField(null=True) 
     15 
     16    def __unicode__(self): 
     17        return u'%i, %.3f' % (self.integer, self.float) 
     18 
     19# 
     20# A more ordinary use case. 
     21# 
     22 
     23class Employee(models.Model): 
     24    firstname = models.CharField(max_length=50) 
     25    lastname = models.CharField(max_length=50) 
     26 
     27    def __unicode__(self): 
     28        return u'%s %s' % (self.firstname, self.lastname) 
     29 
     30class Company(models.Model): 
     31    name = models.CharField(max_length=100) 
     32    num_employees = models.PositiveIntegerField() 
     33    num_chairs = models.PositiveIntegerField() 
     34    ceo = models.ForeignKey( 
     35        Employee, 
     36        related_name='company_ceo_set') 
     37    point_of_contact = models.ForeignKey( 
     38        Employee, 
     39        related_name='company_point_of_contact_set', 
     40        null=True) 
     41 
     42    def __unicode__(self): 
     43        return self.name 
     44 
     45 
     46__test__ = {'API_TESTS': """ 
     47>>> from django.db.models import F 
     48 
     49>>> Number(integer=-1).save() 
     50>>> Number(integer=42).save() 
     51>>> Number(integer=1337).save() 
     52 
     53We can fill a value in all objects with an other value of the same object. 
     54 
     55>>> Number.objects.update(float=F('integer')) 
     56>>> Number.objects.all() 
     57[<Number: -1, -1.000>, <Number: 42, 42.000>, <Number: 1337, 1337.000>] 
     58 
     59We can increment a value of all objects in a query set. 
     60 
     61>>> Number.objects.filter(integer__gt=0).update(integer=F('integer') + 1) 
     62>>> Number.objects.all() 
     63[<Number: -1, -1.000>, <Number: 43, 42.000>, <Number: 1338, 1337.000>] 
     64 
     65We can filter for objects, where a value is not equals the value of an other field. 
     66 
     67>>> Number.objects.exclude(float=F('integer')) 
     68[<Number: 43, 42.000>, <Number: 1338, 1337.000>] 
     69 
     70Complex expressions of different connection types are possible. 
     71 
     72>>> n = Number.objects.create(integer=10, float=123.45) 
     73>>> Number.objects.filter(pk=n.pk).update(float=F('integer') + F('float') * 2) 
     74>>> Number.objects.get(pk=n.pk) 
     75<Number: 10, 256.900> 
     76 
     77All supported operators, work as expected in native and reverse order. 
     78 
     79>>> from operator import add, sub, mul, div, mod, and_, or_ 
     80>>> for op in (add, sub, mul, div, mod, and_, or_): 
     81...     n = Number.objects.create(integer=42, float=15.) 
     82...     Number.objects.filter(pk=n.pk).update( 
     83...         integer=op(F('integer'), 15), float=op(42., F('float'))) 
     84...     Number.objects.get(pk=n.pk) 
     85<Number: 57, 57.000> 
     86<Number: 27, 27.000> 
     87<Number: 630, 630.000> 
     88<Number: 3, 2.800> 
     89<Number: 12, 12.000> 
     90<Number: 10, 10.000> 
     91<Number: 47,