Django

Code

Ticket #2358: mssql.patch

File mssql.patch, 125.7 kB (added by anonymous, 2 years ago)
  • db/backends/ado_mssql/base.py.bak

    old new  
     1""" 
     2ADO MSSQL database backend for Django. 
     3 
     4Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/ 
     5""" 
     6import pythoncom 
     7from django.db.backends import util 
     8try: 
     9    import adodbapi as Database 
     10except ImportError, e: 
     11    from django.core.exceptions import ImproperlyConfigured 
     12    raise ImproperlyConfigured, "Error loading adodbapi module: %s" % e 
     13import datetime 
     14try: 
     15    import mx 
     16except ImportError: 
     17    mx = None 
     18 
     19DatabaseError = Database.DatabaseError 
     20 
     21# We need to use a special Cursor class because adodbapi expects question-mark 
     22# param style, but Django expects "%s". This cursor converts question marks to 
     23# format-string style. 
     24class Cursor(Database.Cursor): 
     25    def executeHelper(self, operation, isStoredProcedureCall, parameters=None): 
     26        if parameters is not None and "%s" in operation: 
     27            operation = operation.replace("%s", "?") 
     28        Database.Cursor.executeHelper(self, operation, isStoredProcedureCall, parameters) 
     29 
     30class Connection(Database.Connection): 
     31    def cursor(self): 
     32        return Cursor(self) 
     33Database.Connection = Connection 
     34 
     35origCVtoP = Database.convertVariantToPython 
     36def variantToPython(variant, adType): 
     37    if type(variant) == bool and adType == 11: 
     38        return variant  # bool not 1/0 
     39    res = origCVtoP(variant, adType) 
     40    if mx is not None and type(res) == mx.DateTime.mxDateTime.DateTimeType: 
     41        # Convert ms.DateTime objects to Python datetime.datetime objects. 
     42        tv = list(res.tuple()[:7]) 
     43        tv[-2] = int(tv[-2]) 
     44        return datetime.datetime(*tuple(tv)) 
     45    if type(res) == float and str(res)[-2:] == ".0": 
     46        return int(res) # If float but int, then int. 
     47    return res 
     48Database.convertVariantToPython = variantToPython 
     49 
     50try: 
     51    # Only exists in Python 2.4+ 
     52    from threading import local 
     53except ImportError: 
     54    # Import copy of _thread_local.py from Python 2.4 
     55    from django.utils._threading_local import local 
     56 
     57class DatabaseWrapper(local): 
     58    def __init__(self, **kwargs): 
     59        self.connection = None 
     60        self.queries = [] 
     61 
     62    def cursor(self): 
     63        from django.conf import settings 
     64        if self.connection is None: 
     65            if settings.DATABASE_NAME == '' or settings.DATABASE_USER == '': 
     66                from django.core.exceptions import ImproperlyConfigured 
     67                raise ImproperlyConfigured, "You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file." 
     68            if not settings.DATABASE_HOST: 
     69                settings.DATABASE_HOST = "127.0.0.1" 
     70            # TODO: Handle DATABASE_PORT. 
     71            conn_string = "PROVIDER=SQLOLEDB;DATA SOURCE=%s;UID=%s;PWD=%s;DATABASE=%s" % (settings.DATABASE_HOST, settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME) 
     72            self.connection = Database.connect(conn_string) 
     73        cursor = self.connection.cursor() 
     74        if settings.DEBUG: 
     75            return util.CursorDebugWrapper(cursor, self) 
     76        return cursor 
     77 
     78    def _commit(self): 
     79        return self.connection.commit() 
     80 
     81    def _rollback(self): 
     82        if self.connection: 
     83            return self.connection.rollback() 
     84 
     85    def close(self): 
     86        if self.connection is not None: 
     87            self.connection.close() 
     88            self.connection = None 
     89 
     90supports_constraints = True 
     91 
     92def quote_name(name): 
     93    if name.startswith('[') and name.endswith(']'): 
     94        return name # Quoting once is enough. 
     95    return '[%s]' % name 
     96 
     97dictfetchone = util.dictfetchone 
     98dictfetchmany = util.dictfetchmany 
     99dictfetchall  = util.dictfetchall 
     100 
     101def get_last_insert_id(cursor, table_name, pk_name): 
     102    cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name)) 
     103    return cursor.fetchone()[0] 
     104 
     105def get_date_extract_sql(lookup_type, table_name): 
     106    # lookup_type is 'year', 'month', 'day' 
     107    return "DATEPART(%s, %s)" % (lookup_type, table_name) 
     108 
     109def get_date_trunc_sql(lookup_type, field_name): 
     110    # lookup_type is 'year', 'month', 'day' 
     111    if lookup_type=='year': 
     112        return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name 
     113    if lookup_type=='month': 
     114        return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name) 
     115    if lookup_type=='day': 
     116        return "Convert(datetime, Convert(varchar(12), %s))" % field_name 
     117 
     118def get_limit_offset_sql(limit, offset=None): 
     119    # TODO: This is a guess. Make sure this is correct. 
     120    sql = "LIMIT %s" % limit 
     121    if offset and offset != 0: 
     122        sql += " OFFSET %s" % offset 
     123    return sql 
     124 
     125def get_random_function_sql(): 
     126    return "RAND()" 
     127 
     128def get_fulltext_search_sql(field_name): 
     129    raise NotImplementedError 
     130 
     131def get_drop_foreignkey_sql(): 
     132    return "DROP CONSTRAINT" 
     133 
     134def get_pk_default_value(): 
     135    return "DEFAULT" 
     136 
     137OPERATOR_MAPPING = { 
     138    'exact': '= %s', 
     139    'iexact': 'LIKE %s', 
     140    'contains': 'LIKE %s', 
     141    'icontains': 'LIKE %s', 
     142    'gt': '> %s', 
     143    'gte': '>= %s', 
     144    'lt': '< %s', 
     145    'lte': '<= %s', 
     146    'startswith': 'LIKE %s', 
     147    'endswith': 'LIKE %s', 
     148    'istartswith': 'LIKE %s', 
     149    'iendswith': 'LIKE %s', 
     150} 
     151""" 
     152ADO MSSQL database backend for Django. 
     153 
     154Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/ 
     155""" 
     156import pythoncom 
     157from django.db.backends import util 
     158try: 
     159    import adodbapi as Database 
     160except ImportError, e: 
     161    from django.core.exceptions import ImproperlyConfigured 
     162    raise ImproperlyConfigured, "Error loading adodbapi module: %s" % e 
     163import datetime 
     164try: 
     165    import mx 
     166except ImportError: 
     167    mx = None 
     168 
     169DatabaseError = Database.DatabaseError 
     170 
     171# We need to use a special Cursor class because adodbapi expects question-mark 
     172# param style, but Django expects "%s". This cursor converts question marks to 
     173# format-string style. 
     174class Cursor(Database.Cursor): 
     175    def executeHelper(self, operation, isStoredProcedureCall, parameters=None): 
     176        if parameters is not None and "%s" in operation: 
     177            operation = operation.replace("%s", "?") 
     178        Database.Cursor.executeHelper(self, operation, isStoredProcedureCall, parameters) 
     179 
     180class Connection(Database.Connection): 
     181    def cursor(self): 
     182        return Cursor(self) 
     183Database.Connection = Connection 
     184 
     185origCVtoP = Database.convertVariantToPython 
     186def variantToPython(variant, adType): 
     187    if type(variant) == bool and adType == 11: 
     188        return variant  # bool not 1/0 
     189    res = origCVtoP(variant, adType) 
     190    if mx is not None and type(res) == mx.DateTime.mxDateTime.DateTimeType: 
     191        # Convert ms.DateTime objects to Python datetime.datetime objects. 
     192        tv = list(res.tuple()[:7]) 
     193        tv[-2] = int(tv[-2]) 
     194        return datetime.datetime(*tuple(tv)) 
     195    if type(res) == float and str(res)[-2:] == ".0": 
     196        return int(res) # If float but int, then int. 
     197    return res 
     198Database.convertVariantToPython = variantToPython 
     199 
     200try: 
     201    # Only exists in Python 2.4+ 
     202    from threading import local 
     203except ImportError: 
     204    # Import copy of _thread_local.py from Python 2.4 
     205    from django.utils._threading_local import local 
     206 
     207class DatabaseWrapper(local): 
     208    def __init__(self, **kwargs): 
     209        self.connection = None 
     210        self.queries = [] 
     211 
     212    def cursor(self): 
     213        from django.conf import settings 
     214        if self.connection is None: 
     215            if settings.DATABASE_NAME == '' or settings.DATABASE_USER == '': 
     216                from django.core.exceptions import ImproperlyConfigured 
     217                raise ImproperlyConfigured, "You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file." 
     218            if not settings.DATABASE_HOST: 
     219                settings.DATABASE_HOST = "127.0.0.1" 
     220            # TODO: Handle DATABASE_PORT. 
     221            conn_string = "PROVIDER=SQLOLEDB;DATA SOURCE=%s;UID=%s;PWD=%s;DATABASE=%s" % (settings.DATABASE_HOST, settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME) 
     222            self.connection = Database.connect(conn_string) 
     223        cursor = self.connection.cursor() 
     224        if settings.DEBUG: 
     225            return util.CursorDebugWrapper(cursor, self) 
     226        return cursor 
     227 
     228    def _commit(self): 
     229        return self.connection.commit() 
     230 
     231    def _rollback(self): 
     232        if self.connection: 
     233            return self.connection.rollback() 
     234 
     235    def close(self): 
     236        if self.connection is not None: 
     237            self.connection.close() 
     238            self.connection = None 
     239 
     240supports_constraints = True 
     241 
     242def quote_name(name): 
     243    if name.startswith('[') and name.endswith(']'): 
     244        return name # Quoting once is enough. 
     245    return '[%s]' % name 
     246 
     247dictfetchone = util.dictfetchone 
     248dictfetchmany = util.dictfetchmany 
     249dictfetchall  = util.dictfetchall 
     250 
     251def get_last_insert_id(cursor, table_name, pk_name): 
     252    cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name)) 
     253    return cursor.fetchone()[0] 
     254 
     255def get_date_extract_sql(lookup_type, table_name): 
     256    # lookup_type is 'year', 'month', 'day' 
     257    return "DATEPART(%s, %s)" % (lookup_type, table_name) 
     258 
     259def get_date_trunc_sql(lookup_type, field_name): 
     260    # lookup_type is 'year', 'month', 'day' 
     261    if lookup_type=='year': 
     262        return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name 
     263    if lookup_type=='month': 
     264        return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name) 
     265    if lookup_type=='day': 
     266        return "Convert(datetime, Convert(varchar(12), %s))" % field_name 
     267 
     268def get_limit_offset_sql(limit, offset=None): 
     269    # TODO: This is a guess. Make sure this is correct. 
     270    sql = "LIMIT %s" % limit 
     271    if offset and offset != 0: 
     272        sql += " OFFSET %s" % offset 
     273    return sql 
     274 
     275def get_random_function_sql(): 
     276    return "RAND()" 
     277 
     278def get_fulltext_search_sql(field_name): 
     279    raise NotImplementedError 
     280 
     281def get_drop_foreignkey_sql(): 
     282    return "DROP CONSTRAINT" 
     283 
     284def get_pk_default_value(): 
     285    return "DEFAULT" 
     286 
     287OPERATOR_MAPPING = { 
     288    'exact': '= %s', 
     289    'iexact': 'LIKE %s', 
     290    'contains': 'LIKE %s', 
     291    'icontains': 'LIKE %s', 
     292    'gt': '> %s', 
     293    'gte': '>= %s', 
     294    'lt': '< %s', 
     295    'lte': '<= %s', 
     296    'startswith': 'LIKE %s', 
     297    'endswith': 'LIKE %s', 
     298    'istartswith': 'LIKE %s', 
     299    'iendswith': 'LIKE %s', 
     300} 
  • db/backends/ado_mssql/introspection.py.bak

    old new  
     1def get_table_list(cursor): 
     2    raise NotImplementedError 
     3 
     4def get_table_description(cursor, table_name): 
     5    raise NotImplementedError 
     6 
     7def get_relations(cursor, table_name): 
     8    raise NotImplementedError 
     9 
     10def get_indexes(cursor, table_name): 
     11    raise NotImplementedError 
     12 
     13DATA_TYPES_REVERSE = {} 
     14def get_table_list(cursor): 
     15    raise NotImplementedError 
     16 
     17def get_table_description(cursor, table_name): 
     18    raise NotImplementedError 
     19 
     20def get_relations(cursor, table_name): 
     21    raise NotImplementedError 
     22 
     23def get_indexes(cursor, table_name): 
     24    raise NotImplementedError 
     25 
     26DATA_TYPES_REVERSE = {} 
  • db/models/base.py.bak

    old new  
     1import django.db.models.manipulators 
     2import django.db.models.manager 
     3from django.core import validators 
     4from django.core.exceptions import ObjectDoesNotExist 
     5from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist 
     6from django.db.models.fields.related import OneToOneRel, ManyToOneRel 
     7from django.db.models.query import delete_objects 
     8from django.db.models.options import Options, AdminOptions 
     9from django.db import connection, backend, transaction 
     10from django.db.models import signals 
     11from django.db.models.loading import register_models, get_model 
     12from django.dispatch import dispatcher 
     13from django.utils.datastructures import SortedDict 
     14from django.utils.functional import curry 
     15from django.conf import settings 
     16import types 
     17import sys 
     18import os 
     19 
     20class ModelBase(type): 
     21    "Metaclass for all models" 
     22    def __new__(cls, name, bases, attrs): 
     23        # If this isn't a subclass of Model, don't do anything special. 
     24        if not bases or bases == (object,): 
     25            return type.__new__(cls, name, bases, attrs) 
     26 
     27        # Create the class. 
     28        new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')}) 
     29        new_class.add_to_class('_meta', Options(attrs.pop('Meta', None))) 
     30        new_class.add_to_class('DoesNotExist', types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {})) 
     31 
     32        # Build complete list of parents 
     33        for base in bases: 
     34            # TODO: Checking for the presence of '_meta' is hackish. 
     35            if '_meta' in dir(base): 
     36                new_class._meta.parents.append(base) 
     37                new_class._meta.parents.extend(base._meta.parents) 
     38 
     39        model_module = sys.modules[new_class.__module__] 
     40 
     41        if getattr(new_class._meta, 'app_label', None) is None: 
     42            # Figure out the app_label by looking one level up. 
     43            # For 'django.contrib.sites.models', this would be 'sites'. 
     44            new_class._meta.app_label = model_module.__name__.split('.')[-2] 
     45 
     46        # Bail out early if we have already created this class. 
     47        m = get_model(new_class._meta.app_label, name, False) 
     48        if m is not None: 
     49            return m 
     50 
     51        # Add all attributes to the class. 
     52        for obj_name, obj in attrs.items(): 
     53            new_class.add_to_class(obj_name, obj) 
     54 
     55        # Add Fields inherited from parents 
     56        for parent in new_class._meta.parents: 
     57            for field in parent._meta.fields: 
     58                # Only add parent fields if they aren't defined for this class. 
     59                try: 
     60                    new_class._meta.get_field(field.name) 
     61                except FieldDoesNotExist: 
     62                    field.contribute_to_class(new_class, field.name) 
     63 
     64        new_class._prepare() 
     65 
     66        register_models(new_class._meta.app_label, new_class) 
     67        # Because of the way imports happen (recursively), we may or may not be 
     68        # the first class for this model to register with the framework. There 
     69        # should only be one class for each model, so we must always return the 
     70        # registered version. 
     71        return get_model(new_class._meta.app_label, name, False) 
     72 
     73class Model(object): 
     74    __metaclass__ = ModelBase 
     75 
     76    def _get_pk_val(self): 
     77        return getattr(self, self._meta.pk.attname) 
     78 
     79    def __repr__(self): 
     80        return '<%s: %s>' % (self.__class__.__name__, self) 
     81 
     82    def __str__(self): 
     83        return '%s object' % self.__class__.__name__ 
     84 
     85    def __eq__(self, other): 
     86        return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val() 
     87 
     88    def __ne__(self, other): 
     89        return not self.__eq__(other) 
     90 
     91    def __init__(self, *args, **kwargs): 
     92        dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) 
     93        for f in self._meta.fields: 
     94            if isinstance(f.rel, ManyToOneRel): 
     95                try: 
     96                    # Assume object instance was passed in. 
     97                    rel_obj = kwargs.pop(f.name) 
     98                except KeyError: 
     99                    try: 
     100                        # Object instance wasn't passed in -- must be an ID. 
     101                        val = kwargs.pop(f.attname) 
     102                    except KeyError: 
     103                        val = f.get_default() 
     104                else: 
     105                    # Object instance was passed in. 
     106                    # Special case: You can pass in "None" for related objects if it's allowed. 
     107                    if rel_obj is None and f.null: 
     108                        val = None 
     109                    else: 
     110                        try: 
     111                            val = getattr(rel_obj, f.rel.get_related_field().attname) 
     112                        except AttributeError: 
     113                            raise TypeError, "Invalid value: %r should be a %s instance, not a %s" % (f.name, f.rel.to, type(rel_obj)) 
     114                setattr(self, f.attname, val) 
     115            else: 
     116                val = kwargs.pop(f.attname, f.get_default()) 
     117                setattr(self, f.attname, val) 
     118        for prop in kwargs.keys(): 
     119            try: 
     120                if isinstance(getattr(self.__class__, prop), property): 
     121                    setattr(self, prop, kwargs.pop(prop)) 
     122            except AttributeError: 
     123                pass 
     124        if kwargs: 
     125            raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] 
     126        for i, arg in enumerate(args): 
     127            setattr(self, self._meta.fields[i].attname, arg) 
     128        dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self) 
     129 
     130    def add_to_class(cls, name, value): 
     131        if name == 'Admin': 
     132            assert type(value) == types.ClassType, "%r attribute of %s model must be a class, not a %s object" % (name, cls.__name__, type(value)) 
     133            value = AdminOptions(**dict([(k, v) for k, v in value.__dict__.items() if not k.startswith('_')])) 
     134        if hasattr(value, 'contribute_to_class'): 
     135            value.contribute_to_class(cls, name) 
     136        else: 
     137            setattr(cls, name, value) 
     138    add_to_class = classmethod(add_to_class) 
     139 
     140    def _prepare(cls): 
     141        # Creates some methods once self._meta has been populated. 
     142        opts = cls._meta 
     143        opts._prepare(cls) 
     144 
     145        if opts.order_with_respect_to: 
     146            cls.get_next_in_order = curry(cls._get_next_or_previous_in_order, is_next=True) 
     147            cls.get_previous_in_order = curry(cls._get_next_or_previous_in_order, is_next=False) 
     148            setattr(opts.order_with_respect_to.rel.to, 'get_%s_order' % cls.__name__.lower(), curry(method_get_order, cls)) 
     149            setattr(opts.order_with_respect_to.rel.to, 'set_%s_order' % cls.__name__.lower(), curry(method_set_order, cls)) 
     150 
     151        # Give the class a docstring -- its definition. 
     152        if cls.__doc__ is None: 
     153            cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join([f.attname for f in opts.fields])) 
     154 
     155        if hasattr(cls, 'get_absolute_url'): 
     156            cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url) 
     157 
     158        dispatcher.send(signal=signals.class_prepared, sender=cls) 
     159 
     160    _prepare = classmethod(_prepare) 
     161 
     162    def save(self): 
     163        dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self) 
     164 
     165        non_pks = [f for f in self._meta.fields if not f.primary_key] 
     166        cursor = connection.cursor() 
     167 
     168        # First, try an UPDATE. If that doesn't update anything, do an INSERT. 
     169        pk_val = self._get_pk_val() 
     170        pk_set = bool(pk_val) 
     171        record_exists = True 
     172        if pk_set: 
     173            # Determine whether a record with the primary key already exists. 
     174            cursor.execute("SELECT 1 FROM %s WHERE %s=%%s" %  
     175                (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val]) 
     176            # If it does already exist, do an UPDATE. 
     177            if cursor.fetchone(): 
     178                db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks] 
     179                if db_values: 
     180                    cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \ 
     181                        (backend.quote_name(self._meta.db_table), 
     182                        ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]), 
     183                        backend.quote_name(self._meta.pk.column)), 
     184                        db_values + [pk_val]) 
     185            else: 
     186                record_exists = False 
     187        if not pk_set or not record_exists: 
     188            field_names = [backend.quote_name(f.column) for f in self._meta.fields if not isinstance(f, AutoField)] 
     189            db_values = [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)] 
     190            # If the PK has been manually set, respect that. 
     191            if pk_set: 
     192                field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)] 
     193                db_values += [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)] 
     194            placeholders = ['%s'] * len(field_names) 
     195            if self._meta.order_with_respect_to: 
     196                field_names.append(backend.quote_name('_order')) 
     197                # TODO: This assumes the database supports subqueries. 
     198                placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \ 
     199                    (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column))) 
     200                db_values.append(getattr(self, self._meta.order_with_respect_to.attname)) 
     201            if db_values: 
     202                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ 
     203                    (backend.quote_name(self._meta.db_table), ','.join(field_names), 
     204                    ','.join(placeholders)), db_values) 
     205            else: 
     206                # Create a new record with defaults for everything. 
     207                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % 
     208                    (backend.quote_name(self._meta.db_table), 
     209                     backend.quote_name(self._meta.pk.column), 
     210                     backend.get_pk_default_value())) 
     211            if self._meta.has_auto_field and not pk_set: 
     212                setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column)) 
     213        transaction.commit_unless_managed() 
     214 
     215        # Run any post-save hooks. 
     216        dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self) 
     217 
     218    save.alters_data = True 
     219 
     220    def validate(self): 
     221        """ 
     222        First coerces all fields on this instance to their proper Python types. 
     223        Then runs validation on every field. Returns a dictionary of 
     224        field_name -> error_list. 
     225        """ 
     226        error_dict = {} 
     227        invalid_python = {} 
     228        for f in self._meta.fields: 
     229            try: 
     230                setattr(self, f.attname, f.to_python(getattr(self, f.attname, f.get_default()))) 
     231            except validators.ValidationError, e: 
     232                error_dict[f.name] = e.messages 
     233                invalid_python[f.name] = 1 
     234        for f in self._meta.fields: 
     235            if f.name in invalid_python: 
     236                continue 
     237            errors = f.validate_full(getattr(self, f.attname, f.get_default()), self.__dict__) 
     238            if errors: 
     239                error_dict[f.name] = errors 
     240        return error_dict 
     241 
     242    def _collect_sub_objects(self, seen_objs): 
     243        """ 
     244        Recursively populates seen_objs with all objects related to this object. 
     245        When done, seen_objs will be in the format: 
     246            {model_class: {pk_val: obj, pk_val: obj, ...}, 
     247             model_class: {pk_val: obj, pk_val: obj, ...}, ...} 
     248        """ 
     249        pk_val = self._get_pk_val() 
     250        if pk_val in seen_objs.setdefault(self.__class__, {}): 
     251            return 
     252        seen_objs.setdefault(self.__class__, {})[pk_val] = self 
     253 
     254        for related in self._meta.get_all_related_objects(): 
     255            rel_opts_name = related.get_accessor_name() 
     256            if isinstance(related.field.rel, OneToOneRel): 
     257                try: 
     258                    sub_obj = getattr(self, rel_opts_name) 
     259                except ObjectDoesNotExist: 
     260                    pass 
     261                else: 
     262                    sub_obj._collect_sub_objects(seen_objs) 
     263            else: 
     264                for sub_obj in getattr(self, rel_opts_name).all(): 
     265                    sub_obj._collect_sub_objects(seen_objs) 
     266 
     267    def delete(self): 
     268        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) 
     269 
     270        # Find all the objects than need to be deleted 
     271        seen_objs = SortedDict() 
     272        self._collect_sub_objects(seen_objs) 
     273 
     274        # Actually delete the objects 
     275        delete_objects(seen_objs) 
     276 
     277    delete.alters_data = True 
     278 
     279    def _get_FIELD_display(self, field): 
     280        value = getattr(self, field.attname) 
     281        return dict(field.choices).get(value, value) 
     282 
     283    def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs): 
     284        op = is_next and '>' or '<' 
     285        where = '(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \ 
     286            (backend.quote_name(field.column), op, backend.quote_name(field.column), 
     287            backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column), op) 
     288        param = str(getattr(self, field.attname)) 
     289        q = self.__class__._default_manager.filter(**kwargs).order_by((not is_next and '-' or '') + field.name, (not is_next and '-' or '') + self._meta.pk.name) 
     290        q._where.append(where) 
     291        q._params.extend([param, param, getattr(self, self._meta.pk.attname)]) 
     292        try: 
     293            return q[0] 
     294        except IndexError: 
     295            raise self.DoesNotExist, "%s matching query does not exist." % self.__class__._meta.object_name 
     296 
     297    def _get_next_or_previous_in_order(self, is_next): 
     298        cachename = "__%s_order_cache" % is_next 
     299        if not hasattr(self, cachename): 
     300            op = is_next and '>' or '<' 
     301            order_field = self._meta.order_with_respect_to 
     302            where = ['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \ 
     303                (backend.quote_name('_order'), op, backend.quote_name('_order'), 
     304                backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), 
     305                '%s=%%s' % backend.quote_name(order_field.column)] 
     306            params = [self._get_pk_val(), getattr(self, order_field.attname)] 
     307            obj = self._default_manager.order_by('_order').extra(where=where, params=params)[:1].get() 
     308            setattr(self, cachename, obj) 
     309        return getattr(self, cachename) 
     310 
     311    def _get_FIELD_filename(self, field): 
     312        if getattr(self, field.attname): # value is not blank 
     313            return os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname)) 
     314        return '' 
     315 
     316    def _get_FIELD_url(self, field): 
     317        if getattr(self, field.attname): # value is not blank 
     318            import urlparse 
     319            return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/') 
     320        return '' 
     321 
     322    def _get_FIELD_size(self, field): 
     323        return os.path.getsize(self._get_FIELD_filename(field)) 
     324 
     325    def _save_FIELD_file(self, field, filename, raw_contents): 
     326        directory = field.get_directory_name() 
     327        try: # Create the date-based directory if it doesn't exist. 
     328            os.makedirs(os.path.join(settings.MEDIA_ROOT, directory)) 
     329        except OSError: # Directory probably already exists. 
     330            pass 
     331        filename = field.get_filename(filename) 
     332 
     333        # If the filename already exists, keep adding an underscore to the name of 
     334        # the file until the filename doesn't exist. 
     335        while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)): 
     336            try: 
     337                dot_index = filename.rindex('.') 
     338            except ValueError: # filename has no dot 
     339                filename += '_' 
     340            else: 
     341                filename = filename[:dot_index] + '_' + filename[dot_index:] 
     342 
     343        # Write the file to disk. 
     344        setattr(self, field.attname, filename) 
     345 
     346        full_filename = self._get_FIELD_filename(field) 
     347        fp = open(full_filename, 'wb') 
     348        fp.write(raw_contents) 
     349        fp.close() 
     350 
     351        # Save the width and/or height, if applicable. 
     352        if isinstance(field, ImageField) and (field.width_field or field.height_field): 
     353            from django.utils.images import get_image_dimensions 
     354            width, height = get_image_dimensions(full_filename) 
     355            if field.width_field: 
     356                setattr(self, field.width_field, width) 
     357            if field.height_field: 
     358                setattr(self, field.height_field, height) 
     359 
     360        # Save the object, because it has changed. 
     361        self.save() 
     362 
     363    _save_FIELD_file.alters_data = True 
     364 
     365    def _get_FIELD_width(self, field): 
     366        return self._get_image_dimensions(field)[0] 
     367 
     368    def _get_FIELD_height(self, field): 
     369        return self._get_image_dimensions(field)[1] 
     370 
     371    def _get_image_dimensions(self, field): 
     372        cachename = "__%s_dimensions_cache" % field.name 
     373        if not hasattr(self, cachename): 
     374            from django.utils.images import get_image_dimensions 
     375            filename = self._get_FIELD_filename(field) 
     376            setattr(self, cachename, get_image_dimensions(filename)) 
     377        return getattr(self, cachename) 
     378 
     379############################################ 
     380# HELPER FUNCTIONS (CURRIED MODEL METHODS) # 
     381############################################ 
     382 
     383# ORDERING METHODS ######################### 
     384 
     385def method_set_order(ordered_obj, self, id_list): 
     386    cursor = connection.cursor() 
     387    # Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s" 
     388    sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \ 
     389        (backend.quote_name(ordered_obj._meta.db_table), backend.quote_name('_order'), 
     390        backend.quote_name(ordered_obj._meta.order_with_respect_to.column), 
     391        backend.quote_name(ordered_obj._meta.pk.column)) 
     392    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name) 
     393    cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)]) 
     394    transaction.commit_unless_managed() 
     395 
     396def method_get_order(ordered_obj, self): 
     397    cursor = connection.cursor() 
     398    # Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order" 
     399    sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \ 
     400        (backend.quote_name(ordered_obj._meta.pk.column), 
     401        backend.quote_name(ordered_obj._meta.db_table), 
     402        backend.quote_name(ordered_obj._meta.order_with_respect_to.column), 
     403        backend.quote_name('_order')) 
     404    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name) 
     405    cursor.execute(sql, [rel_val]) 
     406    return [r[0] for r in cursor.fetchall()] 
     407 
     408############################################## 
     409# HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) # 
     410############################################## 
     411 
     412def get_absolute_url(opts, func, self): 
     413    return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self) 
     414import django.db.models.manipulators 
     415import django.db.models.manager 
     416from django.core import validators 
     417from django.core.exceptions import ObjectDoesNotExist 
     418from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist 
     419from django.db.models.fields.related import OneToOneRel, ManyToOneRel 
     420from django.db.models.query import delete_objects 
     421from django.db.models.options import Options, AdminOptions 
     422from django.db import connection, backend, transaction 
     423from django.db.models import signals 
     424from django.db.models.loading import register_models, get_model 
     425from django.dispatch import dispatcher 
     426from django.utils.datastructures import SortedDict 
     427from django.utils.functional import curry 
     428from django.conf import settings 
     429import types 
     430import sys 
     431import os 
     432 
     433class ModelBase(type): 
     434    "Metaclass for all models" 
     435    def __new__(cls, name, bases, attrs): 
     436        # If this isn't a subclass of Model, don't do anything special. 
     437        if not bases or bases == (object,): 
     438            return type.__new__(cls, name, bases, attrs) 
     439 
     440        # Create the class. 
     441        new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')}) 
     442        new_class.add_to_class('_meta', Options(attrs.pop('Meta', None))) 
     443        new_class.add_to_class('DoesNotExist', types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {})) 
     444 
     445        # Build complete list of parents 
     446        for base in bases: 
     447            # TODO: Checking for the presence of '_meta' is hackish. 
     448            if '_meta' in dir(base): 
     449                new_class._meta.parents.append(base) 
     450                new_class._meta.parents.extend(base._meta.parents) 
     451 
     452        model_module = sys.modules[new_class.__module__] 
     453 
     454        if getattr(new_class._meta, 'app_label', None) is None: 
     455            # Figure out the app_label by looking one level up. 
     456            # For 'django.contrib.sites.models', this would be 'sites'. 
     457            new_class._meta.app_label = model_module.__name__.split('.')[-2] 
     458 
     459        # Bail out early if we have already created this class. 
     460        m = get_model(new_class._meta.app_label, name, False) 
     461        if m is not None: 
     462            return m 
     463 
     464        # Add all attributes to the class. 
     465        for obj_name, obj in attrs.items(): 
     466            new_class.add_to_class(obj_name, obj) 
     467 
     468        # Add Fields inherited from parents 
     469        for parent in new_class._meta.parents: 
     470            for field in parent._meta.fields: 
     471                # Only add parent fields if they aren't defined for this class. 
     472                try: 
     473                    new_class._meta.get_field(field.name) 
     474                except FieldDoesNotExist: 
     475                    field.contribute_to_class(new_class, field.name) 
     476 
     477        new_class._prepare() 
     478 
     479        register_models(new_class._meta.app_label, new_class) 
     480        # Because of the way imports happen (recursively), we may or may not be 
     481        # the first class for this model to register with the framework. There 
     482        # should only be one class for each model, so we must always return the 
     483        # registered version. 
     484        return get_model(new_class._meta.app_label, name, False) 
     485 
     486class Model(object): 
     487    __metaclass__ = ModelBase 
     488 
     489    def _get_pk_val(self): 
     490        return getattr(self, self._meta.pk.attname) 
     491 
     492    def __repr__(self): 
     493        return '<%s: %s>' % (self.__class__.__name__, self) 
     494 
     495    def __str__(self): 
     496        return '%s object' % self.__class__.__name__ 
     497 
     498    def __eq__(self, other): 
     499        return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val() 
     500 
     501    def __ne__(self, other): 
     502        return not self.__eq__(other) 
     503 
     504    def __init__(self, *args, **kwargs): 
     505        dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) 
     506        for f in self._meta.fields: 
     507            if isinstance(f.rel, ManyToOneRel): 
     508                try: 
     509                    # Assume object instance was passed in. 
     510                    rel_obj = kwargs.pop(f.name) 
     511                except KeyError: 
     512                    try: 
     513                        # Object instance wasn't passed in -- must be an ID. 
     514                        val = kwargs.pop(f.attname) 
     515                    except KeyError: 
     516                        val = f.get_default() 
     517                else: 
     518                    # Object instance was passed in. 
     519                    # Special case: You can pass in "None" for related objects if it's allowed. 
     520                    if rel_obj is None and f.null: 
     521                        val = None 
     522                    else: 
     523                        try: 
     524                            val = getattr(rel_obj, f.rel.get_related_field().attname) 
     525                        except AttributeError: 
     526                            raise TypeError, "Invalid value: %r should be a %s instance, not a %s" % (f.name, f.rel.to, type(rel_obj)) 
     527                setattr(self, f.attname, val) 
     528            else: 
     529                val = kwargs.pop(f.attname, f.get_default()) 
     530                setattr(self, f.attname, val) 
     531        for prop in kwargs.keys(): 
     532            try: 
     533                if isinstance(getattr(self.__class__, prop), property): 
     534                    setattr(self, prop, kwargs.pop(prop)) 
     535            except AttributeError: 
     536                pass 
     537        if kwargs: 
     538            raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] 
     539        for i, arg in enumerate(args): 
     540            setattr(self, self._meta.fields[i].attname, arg) 
     541        dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self) 
     542 
     543    def add_to_class(cls, name, value): 
     544        if name == 'Admin': 
     545            assert type(value) == types.ClassType, "%r attribute of %s model must be a class, not a %s object" % (name, cls.__name__, type(value)) 
     546            value = AdminOptions(**dict([(k, v) for k, v in value.__dict__.items() if not k.startswith('_')])) 
     547        if hasattr(value, 'contribute_to_class'): 
     548            value.contribute_to_class(cls, name) 
     549        else: 
     550            setattr(cls, name, value) 
     551    add_to_class = classmethod(add_to_class) 
     552 
     553    def _prepare(cls): 
     554        # Creates some methods once self._meta has been populated. 
     555        opts = cls._meta 
     556        opts._prepare(cls) 
     557 
     558        if opts.order_with_respect_to: 
     559            cls.get_next_in_order = curry(cls._get_next_or_previous_in_order, is_next=True) 
     560            cls.get_previous_in_order = curry(cls._get_next_or_previous_in_order, is_next=False) 
     561            setattr(opts.order_with_respect_to.rel.to, 'get_%s_order' % cls.__name__.lower(), curry(method_get_order, cls)) 
     562            setattr(opts.order_with_respect_to.rel.to, 'set_%s_order' % cls.__name__.lower(), curry(method_set_order, cls)) 
     563 
     564        # Give the class a docstring -- its definition. 
     565        if cls.__doc__ is None: 
     566            cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join([f.attname for f in opts.fields])) 
     567 
     568        if hasattr(cls, 'get_absolute_url'): 
     569            cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url) 
     570 
     571        dispatcher.send(signal=signals.class_prepared, sender=cls) 
     572 
     573    _prepare = classmethod(_prepare) 
     574 
     575    def save(self): 
     576        dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self) 
     577 
     578        non_pks = [f for f in self._meta.fields if not f.primary_key] 
     579        cursor = connection.cursor() 
     580 
     581        # First, try an UPDATE. If that doesn't update anything, do an INSERT. 
     582        pk_val = self._get_pk_val() 
     583        pk_set = bool(pk_val) 
     584        record_exists = True 
     585        if pk_set: 
     586            # Determine whether a record with the primary key already exists. 
     587            cursor.execute("SELECT 1 FROM %s WHERE %s=%%s" %  
     588                (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val]) 
     589            # If it does already exist, do an UPDATE. 
     590            if cursor.fetchone(): 
     591                db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks] 
     592                if db_values: 
     593                    cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \ 
     594                        (backend.quote_name(self._meta.db_table), 
     595                        ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]), 
     596                        backend.quote_name(self._meta.pk.column)), 
     597                        db_values + [pk_val]) 
     598            else: 
     599                record_exists = False 
     600        if not pk_set or not record_exists: 
     601            field_names = [backend.quote_name(f.column) for f in self._meta.fields if not isinstance(f, AutoField)] 
     602            db_values = [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)] 
     603            # If the PK has been manually set, respect that. 
     604            if pk_set: 
     605                field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)] 
    &nbs