Ticket #2358: mssql.patch

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

     
     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

     
     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

     
     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)]
     606                db_values += [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
     607            placeholders = ['%s'] * len(field_names)
     608            if self._meta.order_with_respect_to:
     609                field_names.append(backend.quote_name('_order'))
     610                # TODO: This assumes the database supports subqueries.
     611                placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \
     612                    (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column)))
     613                db_values.append(getattr(self, self._meta.order_with_respect_to.attname))
     614            if db_values:
     615                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
     616                    (backend.quote_name(self._meta.db_table), ','.join(field_names),
     617                    ','.join(placeholders)), db_values)
     618            else:
     619                # Create a new record with defaults for everything.
     620                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" %
     621                    (backend.quote_name(self._meta.db_table),
     622                     backend.quote_name(self._meta.pk.column),
     623                     backend.get_pk_default_value()))
     624            if self._meta.has_auto_field and not pk_set:
     625                setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column))
     626        transaction.commit_unless_managed()
     627
     628        # Run any post-save hooks.
     629        dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self)
     630
     631    save.alters_data = True
     632
     633    def validate(self):
     634        """
     635        First coerces all fields on this instance to their proper Python types.
     636        Then runs validation on every field. Returns a dictionary of
     637        field_name -> error_list.
     638        """
     639        error_dict = {}
     640        invalid_python = {}
     641        for f in self._meta.fields:
     642            try:
     643                setattr(self, f.attname, f.to_python(getattr(self, f.attname, f.get_default())))
     644            except validators.ValidationError, e:
     645                error_dict[f.name] = e.messages
     646                invalid_python[f.name] = 1
     647        for f in self._meta.fields:
     648            if f.name in invalid_python:
     649                continue
     650            errors = f.validate_full(getattr(self, f.attname, f.get_default()), self.__dict__)
     651            if errors:
     652                error_dict[f.name] = errors
     653        return error_dict
     654
     655    def _collect_sub_objects(self, seen_objs):
     656        """
     657        Recursively populates seen_objs with all objects related to this object.
     658        When done, seen_objs will be in the format:
     659            {model_class: {pk_val: obj, pk_val: obj, ...},
     660             model_class: {pk_val: obj, pk_val: obj, ...}, ...}
     661        """
     662        pk_val = self._get_pk_val()
     663        if pk_val in seen_objs.setdefault(self.__class__, {}):
     664            return
     665        seen_objs.setdefault(self.__class__, {})[pk_val] = self
     666
     667        for related in self._meta.get_all_related_objects():
     668            rel_opts_name = related.get_accessor_name()
     669            if isinstance(related.field.rel, OneToOneRel):
     670                try:
     671                    sub_obj = getattr(self, rel_opts_name)
     672                except ObjectDoesNotExist:
     673                    pass
     674                else:
     675                    sub_obj._collect_sub_objects(seen_objs)
     676            else:
     677                for sub_obj in getattr(self, rel_opts_name).all():
     678                    sub_obj._collect_sub_objects(seen_objs)
     679
     680    def delete(self):
     681        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)
     682
     683        # Find all the objects than need to be deleted
     684        seen_objs = SortedDict()
     685        self._collect_sub_objects(seen_objs)
     686
     687        # Actually delete the objects
     688        delete_objects(seen_objs)
     689
     690    delete.alters_data = True
     691
     692    def _get_FIELD_display(self, field):
     693        value = getattr(self, field.attname)
     694        return dict(field.choices).get(value, value)
     695
     696    def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
     697        op = is_next and '>' or '<'
     698        where = '(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \
     699            (backend.quote_name(field.column), op, backend.quote_name(field.column),
     700            backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column), op)
     701        param = str(getattr(self, field.attname))
     702        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)
     703        q._where.append(where)
     704        q._params.extend([param, param, getattr(self, self._meta.pk.attname)])
     705        try:
     706            return q[0]
     707        except IndexError:
     708            raise self.DoesNotExist, "%s matching query does not exist." % self.__class__._meta.object_name
     709
     710    def _get_next_or_previous_in_order(self, is_next):
     711        cachename = "__%s_order_cache" % is_next
     712        if not hasattr(self, cachename):
     713            op = is_next and '>' or '<'
     714            order_field = self._meta.order_with_respect_to
     715            where = ['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \
     716                (backend.quote_name('_order'), op, backend.quote_name('_order'),
     717                backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)),
     718                '%s=%%s' % backend.quote_name(order_field.column)]
     719            params = [self._get_pk_val(), getattr(self, order_field.attname)]
     720            obj = self._default_manager.order_by('_order').extra(where=where, params=params)[:1].get()
     721            setattr(self, cachename, obj)
     722        return getattr(self, cachename)
     723
     724    def _get_FIELD_filename(self, field):
     725        if getattr(self, field.attname): # value is not blank
     726            return os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname))
     727        return ''
     728
     729    def _get_FIELD_url(self, field):
     730        if getattr(self, field.attname): # value is not blank
     731            import urlparse
     732            return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/')
     733        return ''
     734
     735    def _get_FIELD_size(self, field):
     736        return os.path.getsize(self._get_FIELD_filename(field))
     737
     738    def _save_FIELD_file(self, field, filename, raw_contents):
     739        directory = field.get_directory_name()
     740        try: # Create the date-based directory if it doesn't exist.
     741            os.makedirs(os.path.join(settings.MEDIA_ROOT, directory))
     742        except OSError: # Directory probably already exists.
     743            pass
     744        filename = field.get_filename(filename)
     745
     746        # If the filename already exists, keep adding an underscore to the name of
     747        # the file until the filename doesn't exist.
     748        while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)):
     749            try:
     750                dot_index = filename.rindex('.')
     751            except ValueError: # filename has no dot
     752                filename += '_'
     753            else:
     754                filename = filename[:dot_index] + '_' + filename[dot_index:]
     755
     756        # Write the file to disk.
     757        setattr(self, field.attname, filename)
     758
     759        full_filename = self._get_FIELD_filename(field)
     760        fp = open(full_filename, 'wb')
     761        fp.write(raw_contents)
     762        fp.close()
     763
     764        # Save the width and/or height, if applicable.
     765        if isinstance(field, ImageField) and (field.width_field or field.height_field):
     766            from django.utils.images import get_image_dimensions
     767            width, height = get_image_dimensions(full_filename)
     768            if field.width_field:
     769                setattr(self, field.width_field, width)
     770            if field.height_field:
     771                setattr(self, field.height_field, height)
     772
     773        # Save the object, because it has changed.
     774        self.save()
     775
     776    _save_FIELD_file.alters_data = True
     777
     778    def _get_FIELD_width(self, field):
     779        return self._get_image_dimensions(field)[0]
     780
     781    def _get_FIELD_height(self, field):
     782        return self._get_image_dimensions(field)[1]
     783
     784    def _get_image_dimensions(self, field):
     785        cachename = "__%s_dimensions_cache" % field.name
     786        if not hasattr(self, cachename):
     787            from django.utils.images import get_image_dimensions
     788            filename = self._get_FIELD_filename(field)
     789            setattr(self, cachename, get_image_dimensions(filename))
     790        return getattr(self, cachename)
     791
     792############################################
     793# HELPER FUNCTIONS (CURRIED MODEL METHODS) #
     794############################################
     795
     796# ORDERING METHODS #########################
     797
     798def method_set_order(ordered_obj, self, id_list):
     799    cursor = connection.cursor()
     800    # Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s"
     801    sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \
     802        (backend.quote_name(ordered_obj._meta.db_table), backend.quote_name('_order'),
     803        backend.quote_name(ordered_obj._meta.order_with_respect_to.column),
     804        backend.quote_name(ordered_obj._meta.pk.column))
     805    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
     806    cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)])
     807    transaction.commit_unless_managed()
     808
     809def method_get_order(ordered_obj, self):
     810    cursor = connection.cursor()
     811    # Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order"
     812    sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \
     813        (backend.quote_name(ordered_obj._meta.pk.column),
     814        backend.quote_name(ordered_obj._meta.db_table),
     815        backend.quote_name(ordered_obj._meta.order_with_respect_to.column),
     816        backend.quote_name('_order'))
     817    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
     818    cursor.execute(sql, [rel_val])
     819    return [r[0] for r in cursor.fetchall()]
     820
     821##############################################
     822# HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) #
     823##############################################
     824
     825def get_absolute_url(opts, func, self):
     826    return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self)
  • db/models/fields/__init__.py.bak

     
     1from django.db.models import signals
     2from django.dispatch import dispatcher
     3from django.conf import settings
     4from django.core import validators
     5from django import oldforms
     6from django import newforms as forms
     7from django.core.exceptions import ObjectDoesNotExist
     8from django.utils.functional import curry
     9from django.utils.itercompat import tee
     10from django.utils.text import capfirst
     11from django.utils.translation import gettext, gettext_lazy
     12import datetime, os, time
     13
     14class NOT_PROVIDED:
     15    pass
     16
     17# Values for filter_interface.
     18HORIZONTAL, VERTICAL = 1, 2
     19
     20# The values to use for "blank" in SelectFields. Will be appended to the start of most "choices" lists.
     21BLANK_CHOICE_DASH = [("", "---------")]
     22BLANK_CHOICE_NONE = [("", "None")]
     23
     24# prepares a value for use in a LIKE query
     25prep_for_like_query = lambda x: str(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
     26
     27# returns the <ul> class for a given radio_admin value
     28get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
     29
     30class FieldDoesNotExist(Exception):
     31    pass
     32
     33def manipulator_validator_unique(f, opts, self, field_data, all_data):
     34    "Validates that the value is unique for this field."
     35    lookup_type = f.get_validator_unique_lookup_type()
     36    try:
     37        old_obj = self.manager.get(**{lookup_type: field_data})
     38    except ObjectDoesNotExist:
     39        return
     40    if getattr(self, 'original_object', None) and self.original_object._get_pk_val() == old_obj._get_pk_val():
     41        return
     42    raise validators.ValidationError, gettext("%(optname)s with this %(fieldname)s already exists.") % {'optname': capfirst(opts.verbose_name), 'fieldname': f.verbose_name}
     43
     44# A guide to Field parameters:
     45#
     46#   * name:      The name of the field specifed in the model.
     47#   * attname:   The attribute to use on the model object. This is the same as
     48#                "name", except in the case of ForeignKeys, where "_id" is
     49#                appended.
     50#   * db_column: The db_column specified in the model (or None).
     51#   * column:    The database column for this field. This is the same as
     52#                "attname", except if db_column is specified.
     53#
     54# Code that introspects values, or does other dynamic things, should use
     55# attname. For example, this gets the primary key value of object "obj":
     56#
     57#     getattr(obj, opts.pk.attname)
     58
     59class Field(object):
     60
     61    # Designates whether empty strings fundamentally are allowed at the
     62    # database level.
     63    empty_strings_allowed = True
     64
     65    # Tracks each time a Field instance is created. Used to retain order.
     66    creation_counter = 0
     67
     68    def __init__(self, verbose_name=None, name=None, primary_key=False,
     69        maxlength=None, unique=False, blank=False, null=False, db_index=False,
     70        core=False, rel=None, default=NOT_PROVIDED, editable=True,
     71        prepopulate_from=None, unique_for_date=None, unique_for_month=None,
     72        unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
     73        help_text='', db_column=None):
     74        self.name = name
     75        self.verbose_name = verbose_name
     76        self.primary_key = primary_key
     77        self.maxlength, self.unique = maxlength, unique
     78        self.blank, self.null = blank, null
     79        self.core, self.rel, self.default = core, rel, default
     80        self.editable = editable
     81        self.validator_list = validator_list or []
     82        self.prepopulate_from = prepopulate_from
     83        self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
     84        self.unique_for_year = unique_for_year
     85        self._choices = choices or []
     86        self.radio_admin = radio_admin
     87        self.help_text = help_text
     88        self.db_column = db_column
     89
     90        # Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
     91        self.db_index = db_index
     92
     93        # Increase the creation counter, and save our local copy.
     94        self.creation_counter = Field.creation_counter
     95        Field.creation_counter += 1
     96
     97    def __cmp__(self, other):
     98        # This is needed because bisect does not take a comparison function.
     99        return cmp(self.creation_counter, other.creation_counter)
     100
     101    def to_python(self, value):
     102        """
     103        Converts the input value into the expected Python data type, raising
     104        validators.ValidationError if the data can't be converted. Returns the
     105        converted value. Subclasses should override this.
     106        """
     107        return value
     108
     109    def validate_full(self, field_data, all_data):
     110        """
     111        Returns a list of errors for this field. This is the main interface,
     112        as it encapsulates some basic validation logic used by all fields.
     113        Subclasses should implement validate(), not validate_full().
     114        """
     115        if not self.blank and not field_data:
     116            return [gettext_lazy('This field is required.')]
     117        try:
     118            self.validate(field_data, all_data)
     119        except validators.ValidationError, e:
     120            return e.messages
     121        return []
     122
     123    def validate(self, field_data, all_data):
     124        """
     125        Raises validators.ValidationError if field_data has any errors.
     126        Subclasses should override this to specify field-specific validation
     127        logic. This method should assume field_data has already been converted
     128        into the appropriate data type by Field.to_python().
     129        """
     130        pass
     131
     132    def set_attributes_from_name(self, name):
     133        self.name = name
     134        self.attname, self.column = self.get_attname_column()
     135        self.verbose_name = self.verbose_name or (name and name.replace('_', ' '))
     136
     137    def contribute_to_class(self, cls, name):
     138        self.set_attributes_from_name(name)
     139        cls._meta.add_field(self)
     140        if self.choices:
     141            setattr(cls, 'get_%s_display' % self.name, curry(cls._get_FIELD_display, field=self))
     142
     143    def get_attname(self):
     144        return self.name
     145
     146    def get_attname_column(self):
     147        attname = self.get_attname()
     148        column = self.db_column or attname
     149        return attname, column
     150
     151    def get_cache_name(self):
     152        return '_%s_cache' % self.name
     153
     154    def get_internal_type(self):
     155        return self.__class__.__name__
     156
     157    def pre_save(self, model_instance, add):
     158        "Returns field's value just before saving."
     159        return getattr(model_instance, self.attname)
     160
     161    def get_db_prep_save(self, value):
     162        "Returns field's value prepared for saving into a database."
     163        return value
     164
     165    def get_db_prep_lookup(self, lookup_type, value):
     166        "Returns field's value prepared for database lookup."
     167        if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'year', 'month', 'day', 'search'):
     168            return [value]
     169        elif lookup_type in ('range', 'in'):
     170            return value
     171        elif lookup_type in ('contains', 'icontains'):
     172            return ["%%%s%%" % prep_for_like_query(value)]
     173        elif lookup_type == 'iexact':
     174            return [prep_for_like_query(value)]
     175        elif lookup_type in ('startswith', 'istartswith'):
     176            return ["%s%%" % prep_for_like_query(value)]
     177        elif lookup_type in ('endswith', 'iendswith'):
     178            return ["%%%s" % prep_for_like_query(value)]
     179        elif lookup_type == 'isnull':
     180            return []
     181        raise TypeError, "Field has invalid lookup: %s" % lookup_type
     182
     183    def has_default(self):
     184        "Returns a boolean of whether this field has a default value."
     185        return self.default is not NOT_PROVIDED
     186
     187    def get_default(self):
     188        "Returns the default value for this field."
     189        if self.default is not NOT_PROVIDED:
     190            if callable(self.default):
     191                return self.default()
     192            return self.default
     193        if not self.empty_strings_allowed or self.null:
     194            return None
     195        return ""
     196
     197    def get_manipulator_field_names(self, name_prefix):
     198        """
     199        Returns a list of field names that this object adds to the manipulator.
     200        """
     201        return [name_prefix + self.name]
     202
     203    def prepare_field_objs_and_params(self, manipulator, name_prefix):
     204        params = {'validator_list': self.validator_list[:]}
     205        if self.maxlength and not self.choices: # Don't give SelectFields a maxlength parameter.
     206            params['maxlength'] = self.maxlength
     207
     208        if self.choices:
     209            if self.radio_admin:
     210                field_objs = [oldforms.RadioSelectField]
     211                params['ul_class'] = get_ul_class(self.radio_admin)
     212            else:
     213                field_objs = [oldforms.SelectField]
     214
     215            params['choices'] = self.get_choices_default()
     216        else:
     217            field_objs = self.get_manipulator_field_objs()
     218        return (field_objs, params)
     219
     220    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     221        """
     222        Returns a list of oldforms.FormField instances for this field. It
     223        calculates the choices at runtime, not at compile time.
     224
     225        name_prefix is a prefix to prepend to the "field_name" argument.
     226        rel is a boolean specifying whether this field is in a related context.
     227        """
     228        field_objs, params = self.prepare_field_objs_and_params(manipulator, name_prefix)
     229
     230        # Add the "unique" validator(s).
     231        for field_name_list in opts.unique_together:
     232            if field_name_list[0] == self.name:
     233                params['validator_list'].append(getattr(manipulator, 'isUnique%s' % '_'.join(field_name_list)))
     234
     235        # Add the "unique for..." validator(s).
     236        if self.unique_for_date:
     237            params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_date)))
     238        if self.unique_for_month:
     239            params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_month)))
     240        if self.unique_for_year:
     241            params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_year)))
     242        if self.unique or (self.primary_key and not rel):
     243            params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator))
     244
     245        # Only add is_required=True if the field cannot be blank. Primary keys
     246        # are a special case, and fields in a related context should set this
     247        # as False, because they'll be caught by a separate validator --
     248        # RequiredIfOtherFieldGiven.
     249        params['is_required'] = not self.blank and not self.primary_key and not rel
     250
     251        # BooleanFields (CheckboxFields) are a special case. They don't take
     252        # is_required.
     253        if isinstance(self, BooleanField):
     254            del params['is_required']
     255
     256        # If this field is in a related context, check whether any other fields
     257        # in the related object have core=True. If so, add a validator --
     258        # RequiredIfOtherFieldsGiven -- to this FormField.
     259        if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField):
     260            # First, get the core fields, if any.
     261            core_field_names = []
     262            for f in opts.fields:
     263                if f.core and f != self:
     264                    core_field_names.extend(f.get_manipulator_field_names(name_prefix))
     265            # Now, if there are any, add the validator to this FormField.
     266            if core_field_names:
     267                params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, gettext_lazy("This field is required.")))
     268
     269        # Finally, add the field_names.
     270        field_names = self.get_manipulator_field_names(name_prefix)
     271        return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)]
     272
     273    def get_validator_unique_lookup_type(self):
     274        return '%s__exact' % self.name
     275
     276    def get_manipulator_new_data(self, new_data, rel=False):
     277        """
     278        Given the full new_data dictionary (from the manipulator), returns this
     279        field's data.
     280        """
     281        if rel:
     282            return new_data.get(self.name, [self.get_default()])[0]
     283        val = new_data.get(self.name, self.get_default())
     284        if not self.empty_strings_allowed and val == '' and self.null:
     285            val = None
     286        return val
     287
     288    def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH):
     289        "Returns a list of tuples used as SelectField choices for this field."
     290        first_choice = include_blank and blank_choice or []
     291        if self.choices:
     292            return first_choice + list(self.choices)
     293        rel_model = self.rel.to
     294        if hasattr(self.rel, 'get_related_field'):
     295            lst = [(getattr(x, self.rel.get_related_field().attname), str(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
     296        else:
     297            lst = [(x._get_pk_val(), str(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
     298        return first_choice + lst
     299
     300    def get_choices_default(self):
     301        if self.radio_admin:
     302            return self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)
     303        else:
     304            return self.get_choices()
     305
     306    def _get_val_from_obj(self, obj):
     307        if obj:
     308            return getattr(obj, self.attname)
     309        else:
     310            return self.get_default()
     311
     312    def flatten_data(self, follow, obj=None):
     313        """
     314        Returns a dictionary mapping the field's manipulator field names to its
     315        "flattened" string values for the admin view. obj is the instance to
     316        extract the values from.
     317        """
     318        return {self.attname: self._get_val_from_obj(obj)}
     319
     320    def get_follow(self, override=None):
     321        if override != None:
     322            return override
     323        else:
     324            return self.editable
     325
     326    def bind(self, fieldmapping, original, bound_field_class):
     327        return bound_field_class(self, fieldmapping, original)
     328
     329    def _get_choices(self):
     330        if hasattr(self._choices, 'next'):
     331            choices, self._choices = tee(self._choices)
     332            return choices
     333        else:
     334            return self._choices
     335    choices = property(_get_choices)
     336
     337    def formfield(self):
     338        "Returns a django.newforms.Field instance for this database Field."
     339        # TODO: This is just a temporary default during development.
     340        return forms.CharField(required=not self.blank, label=capfirst(self.verbose_name))
     341
     342class AutoField(Field):
     343    empty_strings_allowed = False
     344    def __init__(self, *args, **kwargs):
     345        assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__
     346        kwargs['blank'] = True
     347        Field.__init__(self, *args, **kwargs)
     348
     349    def to_python(self, value):
     350        if value is None:
     351            return value
     352        try:
     353            return int(value)
     354        except (TypeError, ValueError):
     355            raise validators.ValidationError, gettext("This value must be an integer.")
     356
     357    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     358        if not rel:
     359            return [] # Don't add a FormField unless it's in a related context.
     360        return Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
     361
     362    def get_manipulator_field_objs(self):
     363        return [oldforms.HiddenField]
     364
     365    def get_manipulator_new_data(self, new_data, rel=False):
     366        # Never going to be called
     367        # Not in main change pages
     368        # ignored in related context
     369        if not rel:
     370            return None
     371        return Field.get_manipulator_new_data(self, new_data, rel)
     372
     373    def contribute_to_class(self, cls, name):
     374        assert not cls._meta.has_auto_field, "A model can't have more than one AutoField."
     375        super(AutoField, self).contribute_to_class(cls, name)
     376        cls._meta.has_auto_field = True
     377
     378    def formfield(self):
     379        return None
     380
     381class BooleanField(Field):
     382    def __init__(self, *args, **kwargs):
     383        kwargs['blank'] = True
     384        Field.__init__(self, *args, **kwargs)
     385
     386    def to_python(self, value):
     387        if value in (True, False): return value
     388        if value in ('t', 'True', '1'): return True
     389        if value in ('f', 'False', '0'): return False
     390        raise validators.ValidationError, gettext("This value must be either True or False.")
     391
     392    def get_manipulator_field_objs(self):
     393        return [oldforms.CheckboxField]
     394
     395    def formfield(self):
     396        return forms.BooleanField(required=not self.blank, label=capfirst(self.verbose_name))
     397
     398class CharField(Field):
     399    def get_manipulator_field_objs(self):
     400        return [oldforms.TextField]
     401
     402    def to_python(self, value):
     403        if isinstance(value, basestring):
     404            return value
     405        if value is None:
     406            if self.null:
     407                return value
     408            else:
     409                raise validators.ValidationError, gettext_lazy("This field cannot be null.")
     410        return str(value)
     411
     412    def formfield(self):
     413        return forms.CharField(max_length=self.maxlength, required=not self.blank, label=capfirst(self.verbose_name))
     414
     415# TODO: Maybe move this into contrib, because it's specialized.
     416class CommaSeparatedIntegerField(CharField):
     417    def get_manipulator_field_objs(self):
     418        return [oldforms.CommaSeparatedIntegerField]
     419
     420class DateField(Field):
     421    empty_strings_allowed = False
     422    def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
     423        self.auto_now, self.auto_now_add = auto_now, auto_now_add
     424        #HACKs : auto_now_add/auto_now should be done as a default or a pre_save.
     425        if auto_now or auto_now_add:
     426            kwargs['editable'] = False
     427            kwargs['blank'] = True
     428        Field.__init__(self, verbose_name, name, **kwargs)
     429
     430    def to_python(self, value):
     431        if isinstance(value, datetime.datetime):
     432            return value.date()
     433        if isinstance(value, datetime.date):
     434            return value
     435        validators.isValidANSIDate(value, None)
     436        try:
     437            return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3])
     438        except ValueError:
     439            raise validators.ValidationError, gettext('Enter a valid date in YYYY-MM-DD format.')
     440
     441    def get_db_prep_lookup(self, lookup_type, value):
     442        if lookup_type == 'range':
     443            value = [str(v) for v in value]
     444        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte') and hasattr(value, 'strftime'):
     445            value = value.strftime('%Y-%m-%d')
     446        else:
     447            value = str(value)
     448        return Field.get_db_prep_lookup(self, lookup_type, value)
     449
     450    def pre_save(self, model_instance, add):
     451        if self.auto_now or (self.auto_now_add and add):
     452            value = datetime.datetime.now()
     453            setattr(model_instance, self.attname, value)
     454            return value
     455        else:
     456            return super(DateField, self).pre_save(model_instance, add)
     457
     458    def contribute_to_class(self, cls, name):
     459        super(DateField,self).contribute_to_class(cls, name)
     460        if not self.null:
     461            setattr(cls, 'get_next_by_%s' % self.name,
     462                curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=True))
     463            setattr(cls, 'get_previous_by_%s' % self.name,
     464                curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False))
     465
     466    # Needed because of horrible auto_now[_add] behaviour wrt. editable
     467    def get_follow(self, override=None):
     468        if override != None:
     469            return override
     470        else:
     471            return self.editable or self.auto_now or self.auto_now_add
     472
     473    def get_db_prep_save(self, value):
     474        # Casts dates into string format for entry into database.
     475        if value is not None:
     476            value = value.strftime('%Y-%m-%d')
     477        return Field.get_db_prep_save(self, value)
     478
     479    def get_manipulator_field_objs(self):
     480        return [oldforms.DateField]
     481
     482    def flatten_data(self, follow, obj = None):
     483        val = self._get_val_from_obj(obj)
     484        return {self.attname: (val is not None and val.strftime("%Y-%m-%d") or '')}
     485
     486    def formfield(self):
     487        return forms.DateField(required=not self.blank, label=capfirst(self.verbose_name))
     488
     489class DateTimeField(DateField):
     490    def to_python(self, value):
     491        if isinstance(value, datetime.datetime):
     492            return value
     493        if isinstance(value, datetime.date):
     494            return datetime.datetime(value.year, value.month, value.day)
     495        try: # Seconds are optional, so try converting seconds first.
     496            return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6])
     497        except ValueError:
     498            try: # Try without seconds.
     499                return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M')[:5])
     500            except ValueError: # Try without hour/minutes/seconds.
     501                try:
     502                    return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3])
     503                except ValueError:
     504                    raise validators.ValidationError, gettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
     505
     506    def get_db_prep_save(self, value):
     507        # Casts dates into string format for entry into database.
     508        if value is not None:
     509            # MySQL will throw a warning if microseconds are given, because it
     510            # doesn't support microseconds.
     511            if (settings.DATABASE_ENGINE == 'mysql' or settings.DATABASE_ENGINE == 'ado_mssql') and hasattr(value, 'microsecond'):
     512                value = value.replace(microsecond=0)
     513            value = str(value)
     514        return Field.get_db_prep_save(self, value)
     515
     516    def get_db_prep_lookup(self, lookup_type, value):
     517        # MSSQL doesn't like microseconds.
     518        if settings.DATABASE_ENGINE == 'ado_mssql' and hasattr(value, 'microsecond'):
     519            value = value.replace(microsecond=0)       
     520        if lookup_type == 'range':
     521            value = [str(v) for v in value]
     522        else:
     523            value = str(value)
     524        return Field.get_db_prep_lookup(self, lookup_type, value)
     525
     526    def get_manipulator_field_objs(self):
     527        return [oldforms.DateField, oldforms.TimeField]
     528
     529    def get_manipulator_field_names(self, name_prefix):
     530        return [name_prefix + self.name + '_date', name_prefix + self.name + '_time']
     531
     532    def get_manipulator_new_data(self, new_data, rel=False):
     533        date_field, time_field = self.get_manipulator_field_names('')
     534        if rel:
     535            d = new_data.get(date_field, [None])[0]
     536            t = new_data.get(time_field, [None])[0]
     537        else:
     538            d = new_data.get(date_field, None)
     539            t = new_data.get(time_field, None)
     540        if d is not None and t is not None:
     541            return datetime.datetime.combine(d, t)
     542        return self.get_default()
     543
     544    def flatten_data(self,follow, obj = None):
     545        val = self._get_val_from_obj(obj)
     546        date_field, time_field = self.get_manipulator_field_names('')
     547        return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''),
     548                time_field: (val is not None and val.strftime("%H:%M:%S") or '')}
     549
     550    def formfield(self):
     551        return forms.DateTimeField(required=not self.blank, label=capfirst(self.verbose_name))
     552
     553class EmailField(CharField):
     554    def __init__(self, *args, **kwargs):
     555        kwargs['maxlength'] = 75
     556        CharField.__init__(self, *args, **kwargs)
     557
     558    def get_internal_type(self):
     559        return "CharField"
     560
     561    def get_manipulator_field_objs(self):
     562        return [oldforms.EmailField]
     563
     564    def validate(self, field_data, all_data):
     565        validators.isValidEmail(field_data, all_data)
     566
     567    def formfield(self):
     568        return forms.EmailField(required=not self.blank, label=capfirst(self.verbose_name))
     569
     570class FileField(Field):
     571    def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
     572        self.upload_to = upload_to
     573        Field.__init__(self, verbose_name, name, **kwargs)
     574
     575    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     576        field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
     577        if not self.blank:
     578            if rel:
     579                # This validator makes sure FileFields work in a related context.
     580                class RequiredFileField(object):
     581                    def __init__(self, other_field_names, other_file_field_name):
     582                        self.other_field_names = other_field_names
     583                        self.other_file_field_name = other_file_field_name
     584                        self.always_test = True
     585                    def __call__(self, field_data, all_data):
     586                        if not all_data.get(self.other_file_field_name, False):
     587                            c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, gettext_lazy("This field is required."))
     588                            c(field_data, all_data)
     589                # First, get the core fields, if any.
     590                core_field_names = []
     591                for f in opts.fields:
     592                    if f.core and f != self:
     593                        core_field_names.extend(f.get_manipulator_field_names(name_prefix))
     594                # Now, if there are any, add the validator to this FormField.
     595                if core_field_names:
     596                    field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
     597            else:
     598                v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, gettext_lazy("This field is required."))
     599                v.always_test = True
     600                field_list[0].validator_list.append(v)
     601                field_list[0].is_required = field_list[1].is_required = False
     602
     603        # If the raw path is passed in, validate it's under the MEDIA_ROOT.
     604        def isWithinMediaRoot(field_data, all_data):
     605            f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
     606            if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))):
     607                raise validators.ValidationError, _("Enter a valid filename.")
     608        field_list[1].validator_list.append(isWithinMediaRoot)
     609        return field_list
     610
     611    def contribute_to_class(self, cls, name):
     612        super(FileField, self).contribute_to_class(cls, name)
     613        setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
     614        setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
     615        setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
     616        setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_contents: instance._save_FIELD_file(self, filename, raw_contents))
     617        dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
     618
     619    def delete_file(self, instance):
     620        if getattr(instance, self.attname):
     621            file_name = getattr(instance, 'get_%s_filename' % self.name)()
     622            # If the file exists and no other object of this type references it,
     623            # delete it from the filesystem.
     624            if os.path.exists(file_name) and \
     625                not instance.__class__._default_manager.filter(**{'%s__exact' % self.name: getattr(instance, self.attname)}):
     626                os.remove(file_name)
     627
     628    def get_manipulator_field_objs(self):
     629        return [oldforms.FileUploadField, oldforms.HiddenField]
     630
     631    def get_manipulator_field_names(self, name_prefix):
     632        return [name_prefix + self.name + '_file', name_prefix + self.name]
     633
     634    def save_file(self, new_data, new_object, original_object, change, rel):
     635        upload_field_name = self.get_manipulator_field_names('')[0]
     636        if new_data.get(upload_field_name, False):
     637            func = getattr(new_object, 'save_%s_file' % self.name)
     638            if rel:
     639                func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"])
     640            else:
     641                func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"])
     642
     643    def get_directory_name(self):
     644        return os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
     645
     646    def get_filename(self, filename):
     647        from django.utils.text import get_valid_filename
     648        f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
     649        return os.path.normpath(f)
     650
     651class FilePathField(Field):
     652    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
     653        self.path, self.match, self.recursive = path, match, recursive
     654        Field.__init__(self, verbose_name, name, **kwargs)
     655
     656    def get_manipulator_field_objs(self):
     657        return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
     658
     659class FloatField(Field):
     660    empty_strings_allowed = False
     661    def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
     662        self.max_digits, self.decimal_places = max_digits, decimal_places
     663        Field.__init__(self, verbose_name, name, **kwargs)
     664
     665    def get_manipulator_field_objs(self):
     666        return [curry(oldforms.FloatField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
     667
     668class ImageField(FileField):
     669    def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
     670        self.width_field, self.height_field = width_field, height_field
     671        FileField.__init__(self, verbose_name, name, **kwargs)
     672
     673    def get_manipulator_field_objs(self):
     674        return [oldforms.ImageUploadField, oldforms.HiddenField]
     675
     676    def contribute_to_class(self, cls, name):
     677        super(ImageField, self).contribute_to_class(cls, name)
     678        # Add get_BLAH_width and get_BLAH_height methods, but only if the
     679        # image field doesn't have width and height cache fields.
     680        if not self.width_field:
     681            setattr(cls, 'get_%s_width' % self.name, curry(cls._get_FIELD_width, field=self))
     682        if not self.height_field:
     683            setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
     684
     685    def save_file(self, new_data, new_object, original_object, change, rel):
     686        FileField.save_file(self, new_data, new_object, original_object, change, rel)
     687        # If the image has height and/or width field(s) and they haven't
     688        # changed, set the width and/or height field(s) back to their original
     689        # values.
     690        if change and (self.width_field or self.height_field):
     691            if self.width_field:
     692                setattr(new_object, self.width_field, getattr(original_object, self.width_field))
     693            if self.height_field:
     694                setattr(new_object, self.height_field, getattr(original_object, self.height_field))
     695            new_object.save()
     696
     697class IntegerField(Field):
     698    empty_strings_allowed = False
     699    def get_manipulator_field_objs(self):
     700        return [oldforms.IntegerField]
     701
     702    def formfield(self):
     703        return forms.IntegerField(required=not self.blank, label=capfirst(self.verbose_name))
     704
     705class IPAddressField(Field):
     706    def __init__(self, *args, **kwargs):
     707        kwargs['maxlength'] = 15
     708        Field.__init__(self, *args, **kwargs)
     709
     710    def get_manipulator_field_objs(self):
     711        return [oldforms.IPAddressField]
     712
     713    def validate(self, field_data, all_data):
     714        validators.isValidIPAddress4(field_data, None)
     715
     716class NullBooleanField(Field):
     717    def __init__(self, *args, **kwargs):
     718        kwargs['null'] = True
     719        Field.__init__(self, *args, **kwargs)
     720
     721    def get_manipulator_field_objs(self):
     722        return [oldforms.NullBooleanField]
     723
     724class PhoneNumberField(IntegerField):
     725    def get_manipulator_field_objs(self):
     726        return [oldforms.PhoneNumberField]
     727
     728    def validate(self, field_data, all_data):
     729        validators.isValidPhone(field_data, all_data)
     730
     731class PositiveIntegerField(IntegerField):
     732    def get_manipulator_field_objs(self):
     733        return [oldforms.PositiveIntegerField]
     734
     735class PositiveSmallIntegerField(IntegerField):
     736    def get_manipulator_field_objs(self):
     737        return [oldforms.PositiveSmallIntegerField]
     738
     739class SlugField(Field):
     740    def __init__(self, *args, **kwargs):
     741        kwargs['maxlength'] = kwargs.get('maxlength', 50)
     742        kwargs.setdefault('validator_list', []).append(validators.isSlug)
     743        # Set db_index=True unless it's been set manually.
     744        if not kwargs.has_key('db_index'):
     745            kwargs['db_index'] = True
     746        Field.__init__(self, *args, **kwargs)
     747
     748    def get_manipulator_field_objs(self):
     749        return [oldforms.TextField]
     750
     751class SmallIntegerField(IntegerField):
     752    def get_manipulator_field_objs(self):
     753        return [oldforms.SmallIntegerField]
     754
     755class TextField(Field):
     756    def get_manipulator_field_objs(self):
     757        return [oldforms.LargeTextField]
     758
     759class TimeField(Field):
     760    empty_strings_allowed = False
     761    def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
     762        self.auto_now, self.auto_now_add = auto_now, auto_now_add
     763        if auto_now or auto_now_add:
     764            kwargs['editable'] = False
     765        Field.__init__(self, verbose_name, name, **kwargs)
     766
     767    def get_db_prep_lookup(self, lookup_type, value):
     768        if lookup_type == 'range':
     769            value = [str(v) for v in value]
     770        else:
     771            value = str(value)
     772        return Field.get_db_prep_lookup(self, lookup_type, value)
     773
     774    def pre_save(self, model_instance, add):
     775        if self.auto_now or (self.auto_now_add and add):
     776            value = datetime.datetime.now().time()
     777            setattr(model_instance, self.attname, value)
     778            return value
     779        else:
     780            return super(TimeField, self).pre_save(model_instance, add)
     781
     782    def get_db_prep_save(self, value):
     783        # Casts dates into string format for entry into database.
     784        if value is not None:
     785            # MySQL will throw a warning if microseconds are given, because it
     786            # doesn't support microseconds.
     787            if settings.DATABASE_ENGINE == 'mysql' or settings.DATABASE_ENGINE == 'ado_mssql':
     788                value = value.replace(microsecond=0)
     789            value = str(value)
     790        return Field.get_db_prep_save(self, value)
     791
     792    def get_manipulator_field_objs(self):
     793        return [oldforms.TimeField]
     794
     795    def flatten_data(self,follow, obj = None):
     796        val = self._get_val_from_obj(obj)
     797        return {self.attname: (val is not None and val.strftime("%H:%M:%S") or '')}
     798
     799    def formfield(self):
     800        return forms.TimeField(required=not self.blank, label=capfirst(self.verbose_name))
     801
     802class URLField(Field):
     803    def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
     804        if verify_exists:
     805            kwargs.setdefault('validator_list', []).append(validators.isExistingURL)
     806        self.verify_exists = verify_exists
     807        Field.__init__(self, verbose_name, name, **kwargs)
     808
     809    def get_manipulator_field_objs(self):
     810        return [oldforms.URLField]
     811
     812    def formfield(self):
     813        return forms.URLField(required=not self.blank, verify_exists=self.verify_exists, label=capfirst(self.verbose_name))
     814
     815class USStateField(Field):
     816    def get_manipulator_field_objs(self):
     817        return [oldforms.USStateField]
     818
     819class XMLField(TextField):
     820    def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
     821        self.schema_path = schema_path
     822        Field.__init__(self, verbose_name, name, **kwargs)
     823
     824    def get_internal_type(self):
     825        return "TextField"
     826
     827    def get_manipulator_field_objs(self):
     828        return [curry(oldforms.XMLLargeTextField, schema_path=self.schema_path)]
     829
     830class OrderingField(IntegerField):
     831    empty_strings_allowed=False
     832    def __init__(self, with_respect_to, **kwargs):
     833        self.wrt = with_respect_to
     834        kwargs['null'] = True
     835        IntegerField.__init__(self, **kwargs )
     836
     837    def get_internal_type(self):
     838        return "IntegerField"
     839
     840    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     841        return [oldforms.HiddenField(name_prefix + self.name)]
     842from django.db.models import signals
     843from django.dispatch import dispatcher
     844from django.conf import settings
     845from django.core import validators
     846from django import oldforms
     847from django import newforms as forms
     848from django.core.exceptions import ObjectDoesNotExist
     849from django.utils.functional import curry
     850from django.utils.itercompat import tee
     851from django.utils.text import capfirst
     852from django.utils.translation import gettext, gettext_lazy
     853import datetime, os, time
     854
     855class NOT_PROVIDED:
     856    pass
     857
     858# Values for filter_interface.
     859HORIZONTAL, VERTICAL = 1, 2
     860
     861# The values to use for "blank" in SelectFields. Will be appended to the start of most "choices" lists.
     862BLANK_CHOICE_DASH = [("", "---------")]
     863BLANK_CHOICE_NONE = [("", "None")]
     864
     865# prepares a value for use in a LIKE query
     866prep_for_like_query = lambda x: str(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
     867
     868# returns the <ul> class for a given radio_admin value
     869get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
     870
     871class FieldDoesNotExist(Exception):
     872    pass
     873
     874def manipulator_validator_unique(f, opts, self, field_data, all_data):
     875    "Validates that the value is unique for this field."
     876    lookup_type = f.get_validator_unique_lookup_type()
     877    try:
     878        old_obj = self.manager.get(**{lookup_type: field_data})
     879    except ObjectDoesNotExist:
     880        return
     881    if getattr(self, 'original_object', None) and self.original_object._get_pk_val() == old_obj._get_pk_val():
     882        return
     883    raise validators.ValidationError, gettext("%(optname)s with this %(fieldname)s already exists.") % {'optname': capfirst(opts.verbose_name), 'fieldname': f.verbose_name}
     884
     885# A guide to Field parameters:
     886#
     887#   * name:      The name of the field specifed in the model.
     888#   * attname:   The attribute to use on the model object. This is the same as
     889#                "name", except in the case of ForeignKeys, where "_id" is
     890#                appended.
     891#   * db_column: The db_column specified in the model (or None).
     892#   * column:    The database column for this field. This is the same as
     893#                "attname", except if db_column is specified.
     894#
     895# Code that introspects values, or does other dynamic things, should use
     896# attname. For example, this gets the primary key value of object "obj":
     897#
     898#     getattr(obj, opts.pk.attname)
     899
     900class Field(object):
     901
     902    # Designates whether empty strings fundamentally are allowed at the
     903    # database level.
     904    empty_strings_allowed = True
     905
     906    # Tracks each time a Field instance is created. Used to retain order.
     907    creation_counter = 0
     908
     909    def __init__(self, verbose_name=None, name=None, primary_key=False,
     910        maxlength=None, unique=False, blank=False, null=False, db_index=False,
     911        core=False, rel=None, default=NOT_PROVIDED, editable=True,
     912        prepopulate_from=None, unique_for_date=None, unique_for_month=None,
     913        unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
     914        help_text='', db_column=None):
     915        self.name = name
     916        self.verbose_name = verbose_name
     917        self.primary_key = primary_key
     918        self.maxlength, self.unique = maxlength, unique
     919        self.blank, self.null = blank, null
     920        self.core, self.rel, self.default = core, rel, default
     921        self.editable = editable
     922        self.validator_list = validator_list or []
     923        self.prepopulate_from = prepopulate_from
     924        self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
     925        self.unique_for_year = unique_for_year
     926        self._choices = choices or []
     927        self.radio_admin = radio_admin
     928        self.help_text = help_text
     929        self.db_column = db_column
     930
     931        # Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
     932        self.db_index = db_index
     933
     934        # Increase the creation counter, and save our local copy.
     935        self.creation_counter = Field.creation_counter
     936        Field.creation_counter += 1
     937
     938    def __cmp__(self, other):
     939        # This is needed because bisect does not take a comparison function.
     940        return cmp(self.creation_counter, other.creation_counter)
     941
     942    def to_python(self, value):
     943        """
     944        Converts the input value into the expected Python data type, raising
     945        validators.ValidationError if the data can't be converted. Returns the
     946        converted value. Subclasses should override this.
     947        """
     948        return value
     949
     950    def validate_full(self, field_data, all_data):
     951        """
     952        Returns a list of errors for this field. This is the main interface,
     953        as it encapsulates some basic validation logic used by all fields.
     954        Subclasses should implement validate(), not validate_full().
     955        """
     956        if not self.blank and not field_data:
     957            return [gettext_lazy('This field is required.')]
     958        try:
     959            self.validate(field_data, all_data)
     960        except validators.ValidationError, e:
     961            return e.messages
     962        return []
     963
     964    def validate(self, field_data, all_data):
     965        """
     966        Raises validators.ValidationError if field_data has any errors.
     967        Subclasses should override this to specify field-specific validation
     968        logic. This method should assume field_data has already been converted
     969        into the appropriate data type by Field.to_python().
     970        """
     971        pass
     972
     973    def set_attributes_from_name(self, name):
     974        self.name = name
     975        self.attname, self.column = self.get_attname_column()
     976        self.verbose_name = self.verbose_name or (name and name.replace('_', ' '))
     977
     978    def contribute_to_class(self, cls, name):
     979        self.set_attributes_from_name(name)
     980        cls._meta.add_field(self)
     981        if self.choices:
     982            setattr(cls, 'get_%s_display' % self.name, curry(cls._get_FIELD_display, field=self))
     983
     984    def get_attname(self):
     985        return self.name
     986
     987    def get_attname_column(self):
     988        attname = self.get_attname()
     989        column = self.db_column or attname
     990        return attname, column
     991
     992    def get_cache_name(self):
     993        return '_%s_cache' % self.name
     994
     995    def get_internal_type(self):
     996        return self.__class__.__name__
     997
     998    def pre_save(self, model_instance, add):
     999        "Returns field's value just before saving."
     1000        return getattr(model_instance, self.attname)
     1001
     1002    def get_db_prep_save(self, value):
     1003        "Returns field's value prepared for saving into a database."
     1004        return value
     1005
     1006    def get_db_prep_lookup(self, lookup_type, value):
     1007        "Returns field's value prepared for database lookup."
     1008        if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'year', 'month', 'day', 'search'):
     1009            return [value]
     1010        elif lookup_type in ('range', 'in'):
     1011            return value
     1012        elif lookup_type in ('contains', 'icontains'):
     1013            return ["%%%s%%" % prep_for_like_query(value)]
     1014        elif lookup_type == 'iexact':
     1015            return [prep_for_like_query(value)]
     1016        elif lookup_type in ('startswith', 'istartswith'):
     1017            return ["%s%%" % prep_for_like_query(value)]
     1018        elif lookup_type in ('endswith', 'iendswith'):
     1019            return ["%%%s" % prep_for_like_query(value)]
     1020        elif lookup_type == 'isnull':
     1021            return []
     1022        raise TypeError, "Field has invalid lookup: %s" % lookup_type
     1023
     1024    def has_default(self):
     1025        "Returns a boolean of whether this field has a default value."
     1026        return self.default is not NOT_PROVIDED
     1027
     1028    def get_default(self):
     1029        "Returns the default value for this field."
     1030        if self.default is not NOT_PROVIDED:
     1031            if callable(self.default):
     1032                return self.default()
     1033            return self.default
     1034        if not self.empty_strings_allowed or self.null:
     1035            return None
     1036        return ""
     1037
     1038    def get_manipulator_field_names(self, name_prefix):
     1039        """
     1040        Returns a list of field names that this object adds to the manipulator.
     1041        """
     1042        return [name_prefix + self.name]
     1043
     1044    def prepare_field_objs_and_params(self, manipulator, name_prefix):
     1045        params = {'validator_list': self.validator_list[:]}
     1046        if self.maxlength and not self.choices: # Don't give SelectFields a maxlength parameter.
     1047            params['maxlength'] = self.maxlength
     1048
     1049        if self.choices:
     1050            if self.radio_admin:
     1051                field_objs = [oldforms.RadioSelectField]
     1052                params['ul_class'] = get_ul_class(self.radio_admin)
     1053            else:
     1054                field_objs = [oldforms.SelectField]
     1055
     1056            params['choices'] = self.get_choices_default()
     1057        else:
     1058            field_objs = self.get_manipulator_field_objs()
     1059        return (field_objs, params)
     1060
     1061    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     1062        """
     1063        Returns a list of oldforms.FormField instances for this field. It
     1064        calculates the choices at runtime, not at compile time.
     1065
     1066        name_prefix is a prefix to prepend to the "field_name" argument.
     1067        rel is a boolean specifying whether this field is in a related context.
     1068        """
     1069        field_objs, params = self.prepare_field_objs_and_params(manipulator, name_prefix)
     1070
     1071        # Add the "unique" validator(s).
     1072        for field_name_list in opts.unique_together:
     1073            if field_name_list[0] == self.name:
     1074                params['validator_list'].append(getattr(manipulator, 'isUnique%s' % '_'.join(field_name_list)))
     1075
     1076        # Add the "unique for..." validator(s).
     1077        if self.unique_for_date:
     1078            params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_date)))
     1079        if self.unique_for_month:
     1080            params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_month)))
     1081        if self.unique_for_year:
     1082            params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_year)))
     1083        if self.unique or (self.primary_key and not rel):
     1084            params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator))
     1085
     1086        # Only add is_required=True if the field cannot be blank. Primary keys
     1087        # are a special case, and fields in a related context should set this
     1088        # as False, because they'll be caught by a separate validator --
     1089        # RequiredIfOtherFieldGiven.
     1090        params['is_required'] = not self.blank and not self.primary_key and not rel
     1091
     1092        # BooleanFields (CheckboxFields) are a special case. They don't take
     1093        # is_required.
     1094        if isinstance(self, BooleanField):
     1095            del params['is_required']
     1096
     1097        # If this field is in a related context, check whether any other fields
     1098        # in the related object have core=True. If so, add a validator --
     1099        # RequiredIfOtherFieldsGiven -- to this FormField.
     1100        if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField):
     1101            # First, get the core fields, if any.
     1102            core_field_names = []
     1103            for f in opts.fields:
     1104                if f.core and f != self:
     1105                    core_field_names.extend(f.get_manipulator_field_names(name_prefix))
     1106            # Now, if there are any, add the validator to this FormField.
     1107            if core_field_names:
     1108                params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, gettext_lazy("This field is required.")))
     1109
     1110        # Finally, add the field_names.
     1111        field_names = self.get_manipulator_field_names(name_prefix)
     1112        return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)]
     1113
     1114    def get_validator_unique_lookup_type(self):
     1115        return '%s__exact' % self.name
     1116
     1117    def get_manipulator_new_data(self, new_data, rel=False):
     1118        """
     1119        Given the full new_data dictionary (from the manipulator), returns this
     1120        field's data.
     1121        """
     1122        if rel:
     1123            return new_data.get(self.name, [self.get_default()])[0]
     1124        val = new_data.get(self.name, self.get_default())
     1125        if not self.empty_strings_allowed and val == '' and self.null:
     1126            val = None
     1127        return val
     1128
     1129    def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH):
     1130        "Returns a list of tuples used as SelectField choices for this field."
     1131        first_choice = include_blank and blank_choice or []
     1132        if self.choices:
     1133            return first_choice + list(self.choices)
     1134        rel_model = self.rel.to
     1135        if hasattr(self.rel, 'get_related_field'):
     1136            lst = [(getattr(x, self.rel.get_related_field().attname), str(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
     1137        else:
     1138            lst = [(x._get_pk_val(), str(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
     1139        return first_choice + lst
     1140
     1141    def get_choices_default(self):
     1142        if self.radio_admin:
     1143            return self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)
     1144        else:
     1145            return self.get_choices()
     1146
     1147    def _get_val_from_obj(self, obj):
     1148        if obj:
     1149            return getattr(obj, self.attname)
     1150        else:
     1151            return self.get_default()
     1152
     1153    def flatten_data(self, follow, obj=None):
     1154        """
     1155        Returns a dictionary mapping the field's manipulator field names to its
     1156        "flattened" string values for the admin view. obj is the instance to
     1157        extract the values from.
     1158        """
     1159        return {self.attname: self._get_val_from_obj(obj)}
     1160
     1161    def get_follow(self, override=None):
     1162        if override != None:
     1163            return override
     1164        else:
     1165            return self.editable
     1166
     1167    def bind(self, fieldmapping, original, bound_field_class):
     1168        return bound_field_class(self, fieldmapping, original)
     1169
     1170    def _get_choices(self):
     1171        if hasattr(self._choices, 'next'):
     1172            choices, self._choices = tee(self._choices)
     1173            return choices
     1174        else:
     1175            return self._choices
     1176    choices = property(_get_choices)
     1177
     1178    def formfield(self):
     1179        "Returns a django.newforms.Field instance for this database Field."
     1180        # TODO: This is just a temporary default during development.
     1181        return forms.CharField(required=not self.blank, label=capfirst(self.verbose_name))
     1182
     1183class AutoField(Field):
     1184    empty_strings_allowed = False
     1185    def __init__(self, *args, **kwargs):
     1186        assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__
     1187        kwargs['blank'] = True
     1188        Field.__init__(self, *args, **kwargs)
     1189
     1190    def to_python(self, value):
     1191        if value is None:
     1192            return value
     1193        try:
     1194            return int(value)
     1195        except (TypeError, ValueError):
     1196            raise validators.ValidationError, gettext("This value must be an integer.")
     1197
     1198    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     1199        if not rel:
     1200            return [] # Don't add a FormField unless it's in a related context.
     1201        return Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
     1202
     1203    def get_manipulator_field_objs(self):
     1204        return [oldforms.HiddenField]
     1205
     1206    def get_manipulator_new_data(self, new_data, rel=False):
     1207        # Never going to be called
     1208        # Not in main change pages
     1209        # ignored in related context
     1210        if not rel:
     1211            return None
     1212        return Field.get_manipulator_new_data(self, new_data, rel)
     1213
     1214    def contribute_to_class(self, cls, name):
     1215        assert not cls._meta.has_auto_field, "A model can't have more than one AutoField."
     1216        super(AutoField, self).contribute_to_class(cls, name)
     1217        cls._meta.has_auto_field = True
     1218
     1219    def formfield(self):
     1220        return None
     1221
     1222class BooleanField(Field):
     1223    def __init__(self, *args, **kwargs):
     1224        kwargs['blank'] = True
     1225        Field.__init__(self, *args, **kwargs)
     1226
     1227    def to_python(self, value):
     1228        if value in (True, False): return value
     1229        if value in ('t', 'True', '1'): return True
     1230        if value in ('f', 'False', '0'): return False
     1231        raise validators.ValidationError, gettext("This value must be either True or False.")
     1232
     1233    def get_manipulator_field_objs(self):
     1234        return [oldforms.CheckboxField]
     1235
     1236    def formfield(self):
     1237        return forms.BooleanField(required=not self.blank, label=capfirst(self.verbose_name))
     1238
     1239class CharField(Field):
     1240    def get_manipulator_field_objs(self):
     1241        return [oldforms.TextField]
     1242
     1243    def to_python(self, value):
     1244        if isinstance(value, basestring):
     1245            return value
     1246        if value is None:
     1247            if self.null:
     1248                return value
     1249            else:
     1250                raise validators.ValidationError, gettext_lazy("This field cannot be null.")
     1251        return str(value)
     1252
     1253    def formfield(self):
     1254        return forms.CharField(max_length=self.maxlength, required=not self.blank, label=capfirst(self.verbose_name))
     1255
     1256# TODO: Maybe move this into contrib, because it's specialized.
     1257class CommaSeparatedIntegerField(CharField):
     1258    def get_manipulator_field_objs(self):
     1259        return [oldforms.CommaSeparatedIntegerField]
     1260
     1261class DateField(Field):
     1262    empty_strings_allowed = False
     1263    def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
     1264        self.auto_now, self.auto_now_add = auto_now, auto_now_add
     1265        #HACKs : auto_now_add/auto_now should be done as a default or a pre_save.
     1266        if auto_now or auto_now_add:
     1267            kwargs['editable'] = False
     1268            kwargs['blank'] = True
     1269        Field.__init__(self, verbose_name, name, **kwargs)
     1270
     1271    def to_python(self, value):
     1272        if isinstance(value, datetime.datetime):
     1273            return value.date()
     1274        if isinstance(value, datetime.date):
     1275            return value
     1276        validators.isValidANSIDate(value, None)
     1277        try:
     1278            return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3])
     1279        except ValueError:
     1280            raise validators.ValidationError, gettext('Enter a valid date in YYYY-MM-DD format.')
     1281
     1282    def get_db_prep_lookup(self, lookup_type, value):
     1283        if lookup_type == 'range':
     1284            value = [str(v) for v in value]
     1285        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte') and hasattr(value, 'strftime'):
     1286            value = value.strftime('%Y-%m-%d')
     1287        else:
     1288            value = str(value)
     1289        return Field.get_db_prep_lookup(self, lookup_type, value)
     1290
     1291    def pre_save(self, model_instance, add):
     1292        if self.auto_now or (self.auto_now_add and add):
     1293            value = datetime.datetime.now()
     1294            setattr(model_instance, self.attname, value)
     1295            return value
     1296        else:
     1297            return super(DateField, self).pre_save(model_instance, add)
     1298
     1299    def contribute_to_class(self, cls, name):
     1300        super(DateField,self).contribute_to_class(cls, name)
     1301        if not self.null:
     1302            setattr(cls, 'get_next_by_%s' % self.name,
     1303                curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=True))
     1304            setattr(cls, 'get_previous_by_%s' % self.name,
     1305                curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False))
     1306
     1307    # Needed because of horrible auto_now[_add] behaviour wrt. editable
     1308    def get_follow(self, override=None):
     1309        if override != None:
     1310            return override
     1311        else:
     1312            return self.editable or self.auto_now or self.auto_now_add
     1313
     1314    def get_db_prep_save(self, value):
     1315        # Casts dates into string format for entry into database.
     1316        if value is not None:
     1317            value = value.strftime('%Y-%m-%d')
     1318        return Field.get_db_prep_save(self, value)
     1319
     1320    def get_manipulator_field_objs(self):
     1321        return [oldforms.DateField]
     1322
     1323    def flatten_data(self, follow, obj = None):
     1324        val = self._get_val_from_obj(obj)
     1325        return {self.attname: (val is not None and val.strftime("%Y-%m-%d") or '')}
     1326
     1327    def formfield(self):
     1328        return forms.DateField(required=not self.blank, label=capfirst(self.verbose_name))
     1329
     1330class DateTimeField(DateField):
     1331    def to_python(self, value):
     1332        if isinstance(value, datetime.datetime):
     1333            return value
     1334        if isinstance(value, datetime.date):
     1335            return datetime.datetime(value.year, value.month, value.day)
     1336        try: # Seconds are optional, so try converting seconds first.
     1337            return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6])
     1338        except ValueError:
     1339            try: # Try without seconds.
     1340                return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M')[:5])
     1341            except ValueError: # Try without hour/minutes/seconds.
     1342                try:
     1343                    return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3])
     1344                except ValueError:
     1345                    raise validators.ValidationError, gettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
     1346
     1347    def get_db_prep_save(self, value):
     1348        # Casts dates into string format for entry into database.
     1349        if value is not None:
     1350            # MySQL will throw a warning if microseconds are given, because it
     1351            # doesn't support microseconds.
     1352            if (settings.DATABASE_ENGINE == 'mysql' or settings.DATABASE_ENGINE == 'ado_mssql') and hasattr(value, 'microsecond'):
     1353                value = value.replace(microsecond=0)
     1354            value = str(value)
     1355        return Field.get_db_prep_save(self, value)
     1356
     1357    def get_db_prep_lookup(self, lookup_type, value):
     1358        # MSSQL doesn't like microseconds.
     1359        if settings.DATABASE_ENGINE == 'ado_mssql' and hasattr(value, 'microsecond'):
     1360            value = value.replace(microsecond=0)       
     1361        if lookup_type == 'range':
     1362            value = [str(v) for v in value]
     1363        else:
     1364            value = str(value)
     1365        return Field.get_db_prep_lookup(self, lookup_type, value)
     1366
     1367    def get_manipulator_field_objs(self):
     1368        return [oldforms.DateField, oldforms.TimeField]
     1369
     1370    def get_manipulator_field_names(self, name_prefix):
     1371        return [name_prefix + self.name + '_date', name_prefix + self.name + '_time']
     1372
     1373    def get_manipulator_new_data(self, new_data, rel=False):
     1374        date_field, time_field = self.get_manipulator_field_names('')
     1375        if rel:
     1376            d = new_data.get(date_field, [None])[0]
     1377            t = new_data.get(time_field, [None])[0]
     1378        else:
     1379            d = new_data.get(date_field, None)
     1380            t = new_data.get(time_field, None)
     1381        if d is not None and t is not None:
     1382            return datetime.datetime.combine(d, t)
     1383        return self.get_default()
     1384
     1385    def flatten_data(self,follow, obj = None):
     1386        val = self._get_val_from_obj(obj)
     1387        date_field, time_field = self.get_manipulator_field_names('')
     1388        return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''),
     1389                time_field: (val is not None and val.strftime("%H:%M:%S") or '')}
     1390
     1391    def formfield(self):
     1392        return forms.DateTimeField(required=not self.blank, label=capfirst(self.verbose_name))
     1393
     1394class EmailField(CharField):
     1395    def __init__(self, *args, **kwargs):
     1396        kwargs['maxlength'] = 75
     1397        CharField.__init__(self, *args, **kwargs)
     1398
     1399    def get_internal_type(self):
     1400        return "CharField"
     1401
     1402    def get_manipulator_field_objs(self):
     1403        return [oldforms.EmailField]
     1404
     1405    def validate(self, field_data, all_data):
     1406        validators.isValidEmail(field_data, all_data)
     1407
     1408    def formfield(self):
     1409        return forms.EmailField(required=not self.blank, label=capfirst(self.verbose_name))
     1410
     1411class FileField(Field):
     1412    def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
     1413        self.upload_to = upload_to
     1414        Field.__init__(self, verbose_name, name, **kwargs)
     1415
     1416    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     1417        field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
     1418        if not self.blank:
     1419            if rel:
     1420                # This validator makes sure FileFields work in a related context.
     1421                class RequiredFileField(object):
     1422                    def __init__(self, other_field_names, other_file_field_name):
     1423                        self.other_field_names = other_field_names
     1424                        self.other_file_field_name = other_file_field_name
     1425                        self.always_test = True
     1426                    def __call__(self, field_data, all_data):
     1427                        if not all_data.get(self.other_file_field_name, False):
     1428                            c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, gettext_lazy("This field is required."))
     1429                            c(field_data, all_data)
     1430                # First, get the core fields, if any.
     1431                core_field_names = []
     1432                for f in opts.fields:
     1433                    if f.core and f != self:
     1434                        core_field_names.extend(f.get_manipulator_field_names(name_prefix))
     1435                # Now, if there are any, add the validator to this FormField.
     1436                if core_field_names:
     1437                    field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
     1438            else:
     1439                v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, gettext_lazy("This field is required."))
     1440                v.always_test = True
     1441                field_list[0].validator_list.append(v)
     1442                field_list[0].is_required = field_list[1].is_required = False
     1443
     1444        # If the raw path is passed in, validate it's under the MEDIA_ROOT.
     1445        def isWithinMediaRoot(field_data, all_data):
     1446            f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
     1447            if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))):
     1448                raise validators.ValidationError, _("Enter a valid filename.")
     1449        field_list[1].validator_list.append(isWithinMediaRoot)
     1450        return field_list
     1451
     1452    def contribute_to_class(self, cls, name):
     1453        super(FileField, self).contribute_to_class(cls, name)
     1454        setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
     1455        setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
     1456        setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
     1457        setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_contents: instance._save_FIELD_file(self, filename, raw_contents))
     1458        dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
     1459
     1460    def delete_file(self, instance):
     1461        if getattr(instance, self.attname):
     1462            file_name = getattr(instance, 'get_%s_filename' % self.name)()
     1463            # If the file exists and no other object of this type references it,
     1464            # delete it from the filesystem.
     1465            if os.path.exists(file_name) and \
     1466                not instance.__class__._default_manager.filter(**{'%s__exact' % self.name: getattr(instance, self.attname)}):
     1467                os.remove(file_name)
     1468
     1469    def get_manipulator_field_objs(self):
     1470        return [oldforms.FileUploadField, oldforms.HiddenField]
     1471
     1472    def get_manipulator_field_names(self, name_prefix):
     1473        return [name_prefix + self.name + '_file', name_prefix + self.name]
     1474
     1475    def save_file(self, new_data, new_object, original_object, change, rel):
     1476        upload_field_name = self.get_manipulator_field_names('')[0]
     1477        if new_data.get(upload_field_name, False):
     1478            func = getattr(new_object, 'save_%s_file' % self.name)
     1479            if rel:
     1480                func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"])
     1481            else:
     1482                func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"])
     1483
     1484    def get_directory_name(self):
     1485        return os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
     1486
     1487    def get_filename(self, filename):
     1488        from django.utils.text import get_valid_filename
     1489        f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
     1490        return os.path.normpath(f)
     1491
     1492class FilePathField(Field):
     1493    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
     1494        self.path, self.match, self.recursive = path, match, recursive
     1495        Field.__init__(self, verbose_name, name, **kwargs)
     1496
     1497    def get_manipulator_field_objs(self):
     1498        return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
     1499
     1500class FloatField(Field):
     1501    empty_strings_allowed = False
     1502    def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
     1503        self.max_digits, self.decimal_places = max_digits, decimal_places
     1504        Field.__init__(self, verbose_name, name, **kwargs)
     1505
     1506    def get_manipulator_field_objs(self):
     1507        return [curry(oldforms.FloatField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
     1508
     1509class ImageField(FileField):
     1510    def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
     1511        self.width_field, self.height_field = width_field, height_field
     1512        FileField.__init__(self, verbose_name, name, **kwargs)
     1513
     1514    def get_manipulator_field_objs(self):
     1515        return [oldforms.ImageUploadField, oldforms.HiddenField]
     1516
     1517    def contribute_to_class(self, cls, name):
     1518        super(ImageField, self).contribute_to_class(cls, name)
     1519        # Add get_BLAH_width and get_BLAH_height methods, but only if the
     1520        # image field doesn't have width and height cache fields.
     1521        if not self.width_field:
     1522            setattr(cls, 'get_%s_width' % self.name, curry(cls._get_FIELD_width, field=self))
     1523        if not self.height_field:
     1524            setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
     1525
     1526    def save_file(self, new_data, new_object, original_object, change, rel):
     1527        FileField.save_file(self, new_data, new_object, original_object, change, rel)
     1528        # If the image has height and/or width field(s) and they haven't
     1529        # changed, set the width and/or height field(s) back to their original
     1530        # values.
     1531        if change and (self.width_field or self.height_field):
     1532            if self.width_field:
     1533                setattr(new_object, self.width_field, getattr(original_object, self.width_field))
     1534            if self.height_field:
     1535                setattr(new_object, self.height_field, getattr(original_object, self.height_field))
     1536            new_object.save()
     1537
     1538class IntegerField(Field):
     1539    empty_strings_allowed = False
     1540    def get_manipulator_field_objs(self):
     1541        return [oldforms.IntegerField]
     1542
     1543    def formfield(self):
     1544        return forms.IntegerField(required=not self.blank, label=capfirst(self.verbose_name))
     1545
     1546class IPAddressField(Field):
     1547    def __init__(self, *args, **kwargs):
     1548        kwargs['maxlength'] = 15
     1549        Field.__init__(self, *args, **kwargs)
     1550
     1551    def get_manipulator_field_objs(self):
     1552        return [oldforms.IPAddressField]
     1553
     1554    def validate(self, field_data, all_data):
     1555        validators.isValidIPAddress4(field_data, None)
     1556
     1557class NullBooleanField(Field):
     1558    def __init__(self, *args, **kwargs):
     1559        kwargs['null'] = True
     1560        Field.__init__(self, *args, **kwargs)
     1561
     1562    def get_manipulator_field_objs(self):
     1563        return [oldforms.NullBooleanField]
     1564
     1565class PhoneNumberField(IntegerField):
     1566    def get_manipulator_field_objs(self):
     1567        return [oldforms.PhoneNumberField]
     1568
     1569    def validate(self, field_data, all_data):
     1570        validators.isValidPhone(field_data, all_data)
     1571
     1572class PositiveIntegerField(IntegerField):
     1573    def get_manipulator_field_objs(self):
     1574        return [oldforms.PositiveIntegerField]
     1575
     1576class PositiveSmallIntegerField(IntegerField):
     1577    def get_manipulator_field_objs(self):
     1578        return [oldforms.PositiveSmallIntegerField]
     1579
     1580class SlugField(Field):
     1581    def __init__(self, *args, **kwargs):
     1582        kwargs['maxlength'] = kwargs.get('maxlength', 50)
     1583        kwargs.setdefault('validator_list', []).append(validators.isSlug)
     1584        # Set db_index=True unless it's been set manually.
     1585        if not kwargs.has_key('db_index'):
     1586            kwargs['db_index'] = True
     1587        Field.__init__(self, *args, **kwargs)
     1588
     1589    def get_manipulator_field_objs(self):
     1590        return [oldforms.TextField]
     1591
     1592class SmallIntegerField(IntegerField):
     1593    def get_manipulator_field_objs(self):
     1594        return [oldforms.SmallIntegerField]
     1595
     1596class TextField(Field):
     1597    def get_manipulator_field_objs(self):
     1598        return [oldforms.LargeTextField]
     1599
     1600class TimeField(Field):
     1601    empty_strings_allowed = False
     1602    def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
     1603        self.auto_now, self.auto_now_add = auto_now, auto_now_add
     1604        if auto_now or auto_now_add:
     1605            kwargs['editable'] = False
     1606        Field.__init__(self, verbose_name, name, **kwargs)
     1607
     1608    def get_db_prep_lookup(self, lookup_type, value):
     1609        if lookup_type == 'range':
     1610            value = [str(v) for v in value]
     1611        else:
     1612            value = str(value)
     1613        return Field.get_db_prep_lookup(self, lookup_type, value)
     1614
     1615    def pre_save(self, model_instance, add):
     1616        if self.auto_now or (self.auto_now_add and add):
     1617            value = datetime.datetime.now().time()
     1618            setattr(model_instance, self.attname, value)
     1619            return value
     1620        else:
     1621            return super(TimeField, self).pre_save(model_instance, add)
     1622
     1623    def get_db_prep_save(self, value):
     1624        # Casts dates into string format for entry into database.
     1625        if value is not None:
     1626            # MySQL will throw a warning if microseconds are given, because it
     1627            # doesn't support microseconds.
     1628            if settings.DATABASE_ENGINE == 'mysql' or settings.DATABASE_ENGINE == 'ado_mssql':
     1629                value = value.replace(microsecond=0)
     1630            value = str(value)
     1631        return Field.get_db_prep_save(self, value)
     1632
     1633    def get_manipulator_field_objs(self):
     1634        return [oldforms.TimeField]
     1635
     1636    def flatten_data(self,follow, obj = None):
     1637        val = self._get_val_from_obj(obj)
     1638        return {self.attname: (val is not None and val.strftime("%H:%M:%S") or '')}
     1639
     1640    def formfield(self):
     1641        return forms.TimeField(required=not self.blank, label=capfirst(self.verbose_name))
     1642
     1643class URLField(Field):
     1644    def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
     1645        if verify_exists:
     1646            kwargs.setdefault('validator_list', []).append(validators.isExistingURL)
     1647        self.verify_exists = verify_exists
     1648        Field.__init__(self, verbose_name, name, **kwargs)
     1649
     1650    def get_manipulator_field_objs(self):
     1651        return [oldforms.URLField]
     1652
     1653    def formfield(self):
     1654        return forms.URLField(required=not self.blank, verify_exists=self.verify_exists, label=capfirst(self.verbose_name))
     1655
     1656class USStateField(Field):
     1657    def get_manipulator_field_objs(self):
     1658        return [oldforms.USStateField]
     1659
     1660class XMLField(TextField):
     1661    def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
     1662        self.schema_path = schema_path
     1663        Field.__init__(self, verbose_name, name, **kwargs)
     1664
     1665    def get_internal_type(self):
     1666        return "TextField"
     1667
     1668    def get_manipulator_field_objs(self):
     1669        return [curry(oldforms.XMLLargeTextField, schema_path=self.schema_path)]
     1670
     1671class OrderingField(IntegerField):
     1672    empty_strings_allowed=False
     1673    def __init__(self, with_respect_to, **kwargs):
     1674        self.wrt = with_respect_to
     1675        kwargs['null'] = True
     1676        IntegerField.__init__(self, **kwargs )
     1677
     1678    def get_internal_type(self):
     1679        return "IntegerField"
     1680
     1681    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     1682        return [oldforms.HiddenField(name_prefix + self.name)]
  • newforms/models.py

    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: newforms\__init__.pyc
    ___________________________________________________________________
    Name: svn:mime-type
       + application/octet-stream
    
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: newforms\fields.pyc
    ___________________________________________________________________
    Name: svn:mime-type
       + application/octet-stream
    
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: newforms\forms.pyc
    ___________________________________________________________________
    Name: svn:mime-type
       + application/octet-stream
    
     
     1"""
     2Helper functions for creating Form classes from Django models
     3and database field objects.
     4"""
     5
     6from forms import BaseForm, DeclarativeFieldsMetaclass, SortedDictFromList
     7
     8__all__ = ('form_for_model', 'form_for_fields')
     9
     10def create(self, save=True):
     11    "Creates and returns model instance according to self.clean_data."
     12    if self.errors:
     13        raise ValueError("The %s could not be created because the data didn't validate." % self._model._meta.object_name)
     14    obj = self._model(**self.clean_data)
     15    if save:
     16        obj.save()
     17    return obj
     18
     19def form_for_model(model):
     20    "Returns a Form class for the given Django model class."
     21    opts = model._meta
     22    field_list = []
     23    for f in opts.fields + opts.many_to_many:
     24        formfield = f.formfield()
     25        if formfield:
     26            field_list.append((f.name, formfield))
     27    fields = SortedDictFromList(field_list)
     28    return type(opts.object_name + 'Form', (BaseForm,), {'fields': fields, '_model': model, 'create': create})
     29
     30def form_for_fields(field_list):
     31    "Returns a Form class for the given list of Django database field instances."
     32    fields = SortedDictFromList([(f.name, f.formfield()) for f in field_list])
     33    return type('FormForFields', (BaseForm,), {'fields': fields})
Back to Top