Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py	(revision 3507)
+++ django/db/models/fields/__init__.py	(working copy)
@@ -617,15 +617,65 @@
     def get_manipulator_field_objs(self):
         return [curry(forms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
 
-class FloatField(Field):
+class DecimalField(Field):
     empty_strings_allowed = False
     def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
         self.max_digits, self.decimal_places = max_digits, decimal_places
         Field.__init__(self, verbose_name, name, **kwargs)
 
+    def to_python(self, value):
+        try:
+            import decimal
+            try:
+                return decimal.Decimal(value)
+            except (decimal.InvalidOperation):
+                raise validators.ValidationError, gettext("This value must be a decimal number.")
+        except ImportError:
+            return str(value)            
+
+    def _format(self, value):
+        if isinstance(value, basestring):
+            return value
+        else:
+            return self.format_number(value)
+    
+    def format_number(self, value):
+        """Formats a number into a string with the requisite number of digits and decimal places."""
+        
+        num_chars = self.max_digits
+        # Allow for a decimal point 
+        if self.decimal_places > 0:
+            num_chars += 1
+        # Allow for a minus sign
+        if value < 0:
+            num_chars += 1
+        
+        return "%.*f" % (self.decimal_places, value)
+
+    def get_db_prep_save(self, value):
+        value = self._format(value)
+
+        return super(DecimalField, self).get_db_prep_save(value)
+
+    def get_db_prep_lookup(self, lookup_type, value):
+        if lookup_type == 'range':
+            value = [self._format(v) for v in value]
+        else:
+            value = self._format(value)
+        return super(DecimalField, self).get_db_prep_lookup(lookup_type, value)
+
     def get_manipulator_field_objs(self):
-        return [curry(forms.FloatField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
+        # TODO change this (because forms.FloatField returns a float)
+        return [curry(forms.DecimalField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
 
+class FloatField(Field):
+    empty_strings_allowed = False
+    def __init__(self, verbose_name=None, name=None, **kwargs):
+        Field.__init__(self, verbose_name, name, **kwargs)
+
+    def get_manipulator_field_objs(self):
+        return [forms.FloatField]
+
 class ImageField(FileField):
     def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
         self.width_field, self.height_field = width_field, height_field
Index: django/db/backends/sqlite3/creation.py
===================================================================
--- django/db/backends/sqlite3/creation.py	(revision 3507)
+++ django/db/backends/sqlite3/creation.py	(working copy)
@@ -8,9 +8,10 @@
     'CommaSeparatedIntegerField':   'varchar(%(maxlength)s)',
     'DateField':                    'date',
     'DateTimeField':                'datetime',
+    'DecimalField':                 'numeric(%(max_digits)s, %(decimal_places)s)',
     'FileField':                    'varchar(100)',
     'FilePathField':                'varchar(100)',
-    'FloatField':                   'numeric(%(max_digits)s, %(decimal_places)s)',
+    'FloatField':                   'numeric',
     'ImageField':                   'varchar(100)',
     'IntegerField':                 'integer',
     'IPAddressField':               'char(15)',
Index: django/db/backends/mysql/base.py
===================================================================
--- django/db/backends/mysql/base.py	(revision 3507)
+++ django/db/backends/mysql/base.py	(working copy)
@@ -22,8 +22,11 @@
     FIELD_TYPE.DATETIME: util.typecast_timestamp,
     FIELD_TYPE.DATE: util.typecast_date,
     FIELD_TYPE.TIME: util.typecast_time,
+    FIELD_TYPE.DECIMAL: None,
+    FIELD_TYPE.NEWDECIMAL: None
 })
 
+
 # This is an extra debug layer over MySQL queries, to display warnings.
 # It's only used when DEBUG=True.
 class MysqlDebugWrapper:
Index: django/db/backends/mysql/introspection.py
===================================================================
--- django/db/backends/mysql/introspection.py	(revision 3507)
+++ django/db/backends/mysql/introspection.py	(working copy)
@@ -75,7 +75,8 @@
 DATA_TYPES_REVERSE = {
     FIELD_TYPE.BLOB: 'TextField',
     FIELD_TYPE.CHAR: 'CharField',
-    FIELD_TYPE.DECIMAL: 'FloatField',
+    FIELD_TYPE.DECIMAL: 'DecimalField',
+    FIELD_TYPE.NEWDECIMAL: 'DecimalField',
     FIELD_TYPE.DATE: 'DateField',
     FIELD_TYPE.DATETIME: 'DateTimeField',
     FIELD_TYPE.DOUBLE: 'FloatField',
Index: django/db/backends/mysql/creation.py
===================================================================
--- django/db/backends/mysql/creation.py	(revision 3507)
+++ django/db/backends/mysql/creation.py	(working copy)
@@ -9,9 +9,10 @@
     'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
     'DateField':         'date',
     'DateTimeField':     'datetime',
+    'DecimalField':      'decimal(%(max_digits)s, %(decimal_places)s)',
     'FileField':         'varchar(100)',
     'FilePathField':     'varchar(100)',
-    'FloatField':        'numeric(%(max_digits)s, %(decimal_places)s)',
+    'FloatField':        'double',
     'ImageField':        'varchar(100)',
     'IntegerField':      'integer',
     'IPAddressField':    'char(15)',
Index: django/forms/__init__.py
===================================================================
--- django/forms/__init__.py	(revision 3507)
+++ django/forms/__init__.py	(working copy)
@@ -739,14 +739,27 @@
             raise validators.CriticalValidationError, gettext("Enter a whole number between 0 and 32,767.")
 
 class FloatField(TextField):
+    def __init__(self, field_name, is_required=False, validator_list=None):
+        if validator_list is None: validator_list = []
+        validator_list = [validators.isValidFloat] + validator_list
+        TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list)
+
+    def html2python(data):
+        if data == '' or data is None:
+            return None
+        return float(data)
+    html2python = staticmethod(html2python)
+
+class DecimalField(TextField):
     def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None):
         if validator_list is None: validator_list = []
         self.max_digits, self.decimal_places = max_digits, decimal_places
-        validator_list = [self.isValidFloat] + validator_list
-        TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list)
+        validator_list = [self.isValidDecimal] + validator_list
+        # Initialise the TextField, making sure it's large enough to fit the number with a - sign and a decimal point.
+        super(DecimalField, self).__init__(field_name, max_digits+2, max_digits+2, is_required, validator_list)
 
-    def isValidFloat(self, field_data, all_data):
-        v = validators.IsValidFloat(self.max_digits, self.decimal_places)
+    def isValidDecimal(self, field_data, all_data):
+        v = validators.IsValidDecimal(self.max_digits, self.decimal_places)
         try:
             v(field_data, all_data)
         except validators.ValidationError, e:
@@ -755,7 +768,14 @@
     def html2python(data):
         if data == '' or data is None:
             return None
-        return float(data)
+        try:
+            import decimal
+            try:
+                return decimal.Decimal(data)
+            except decimal.InvalidOperation, e:
+                raise ValueError, e
+        except ImportError:
+            return str(data)
     html2python = staticmethod(html2python)
 
 ####################
Index: django/core/validators.py
===================================================================
--- django/core/validators.py	(revision 3507)
+++ django/core/validators.py	(working copy)
@@ -24,6 +24,7 @@
     r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
     r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
     r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE)  # domain
+decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
 integer_re = re.compile(r'^-?\d+$')
 ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
 phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)
@@ -342,26 +343,35 @@
         if val != int(val):
             raise ValidationError, gettext("This value must be a power of %s.") % self.power_of
 
-class IsValidFloat(object):
+class IsValidDecimal(object):
     def __init__(self, max_digits, decimal_places):
         self.max_digits, self.decimal_places = max_digits, decimal_places
 
     def __call__(self, field_data, all_data):
-        data = str(field_data)
-        try:
-            float(data)
-        except ValueError:
+        match = decimal_re.search(str(field_data))
+        if not match:
             raise ValidationError, gettext("Please enter a valid decimal number.")
-        if len(data) > (self.max_digits + 1):
+        
+        digits = len(match.group('digits') or '')
+        decimals = len(match.group('decimals') or '')
+        
+        if digits + decimals > self.max_digits:
             raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.",
                 "Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits
-        if (not '.' in data and len(data) > (self.max_digits - self.decimal_places)) or ('.' in data and len(data) > (self.max_digits - (self.decimal_places - len(data.split('.')[1])) + 1)):
+        if digits > (self.max_digits - self.decimal_places):
             raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.",
                 "Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places)
-        if '.' in data and len(data.split('.')[1]) > self.decimal_places:
+        if decimals > self.decimal_places:
             raise ValidationError, ngettext("Please enter a valid decimal number with at most %s decimal place.",
                 "Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places
 
+def isValidFloat(field_data, all_data):
+    data = str(field_data)
+    try:
+        float(data)
+    except ValueError:
+        raise ValidationError, gettext("Please enter a valid floating point number.")
+
 class HasAllowableSize(object):
     """
     Checks that the file-upload field data is a certain size. min_size and
Index: django/core/management.py
===================================================================
--- django/core/management.py	(revision 3507)
+++ django/core/management.py	(working copy)
@@ -756,7 +756,7 @@
                 if field_type == 'CharField' and row[3]:
                     extra_params['maxlength'] = row[3]
 
-                if field_type == 'FloatField':
+                if field_type == 'DecimalField':
                     extra_params['max_digits'] = row[4]
                     extra_params['decimal_places'] = row[5]
 
@@ -830,11 +830,11 @@
                 e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
             if isinstance(f, models.CharField) and f.maxlength in (None, 0):
                 e.add(opts, '"%s": CharFields require a "maxlength" attribute.' % f.name)
-            if isinstance(f, models.FloatField):
+            if isinstance(f, models.DecimalField):
                 if f.decimal_places is None:
-                    e.add(opts, '"%s": FloatFields require a "decimal_places" attribute.' % f.name)
+                    e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name)
                 if f.max_digits is None:
-                    e.add(opts, '"%s": FloatFields require a "max_digits" attribute.' % f.name)
+                    e.add(opts, '"%s": DecimalFields require a "max_digits" attribute.' % f.name)
             if isinstance(f, models.FileField) and not f.upload_to:
                 e.add(opts, '"%s": FileFields require an "upload_to" attribute.' % f.name)
             if isinstance(f, models.ImageField):
Index: django/contrib/admin/templatetags/admin_list.py
===================================================================
--- django/contrib/admin/templatetags/admin_list.py	(revision 3507)
+++ django/contrib/admin/templatetags/admin_list.py	(working copy)
@@ -149,8 +149,8 @@
             elif isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField):
                 BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
                 result_repr = '<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)
-            # FloatFields are special: Zero-pad the decimals.
-            elif isinstance(f, models.FloatField):
+            # DecimalFields are special: Zero-pad the decimals.
+            elif isinstance(f, models.DecimalField):
                 if field_val is not None:
                     result_repr = ('%%.%sf' % f.decimal_places) % field_val
                 else:
Index: django/contrib/admin/views/doc.py
===================================================================
--- django/contrib/admin/views/doc.py	(revision 3507)
+++ django/contrib/admin/views/doc.py	(working copy)
@@ -294,10 +294,11 @@
     'CommaSeparatedIntegerField': _('Comma-separated integers'),
     'DateField'                 : _('Date (without time)'),
     'DateTimeField'             : _('Date (with time)'),
+    'DecimalField'              : _('Decimal number'),
     'EmailField'                : _('E-mail address'),
     'FileField'                 : _('File path'),
     'FilePathField'             : _('File path'),
-    'FloatField'                : _('Decimal number'),
+    'FloatField'                : _('Floating point number'),
     'ForeignKey'                : _('Integer'),
     'ImageField'                : _('File path'),
     'IntegerField'              : _('Integer'),
Index: tests/modeltests/invalid_models/models.py
===================================================================
--- tests/modeltests/invalid_models/models.py	(revision 3507)
+++ tests/modeltests/invalid_models/models.py	(working copy)
@@ -8,7 +8,7 @@
 
 class FieldErrors(models.Model):
     charfield = models.CharField()
-    floatfield = models.FloatField()
+    decimalfield = models.DecimalField()
     filefield = models.FileField()
     prepopulate = models.CharField(maxlength=10, prepopulate_from='bad')
     choices = models.CharField(maxlength=10, choices='bad')
@@ -79,8 +79,8 @@
 
 
 error_log = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute.
-invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places" attribute.
-invalid_models.fielderrors: "floatfield": FloatFields require a "max_digits" attribute.
+invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute.
+invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute.
 invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
 invalid_models.fielderrors: "prepopulate": prepopulate_from should be a list or tuple.
 invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list).
Index: docs/forms.txt
===================================================================
--- docs/forms.txt	(revision 3507)
+++ docs/forms.txt	(working copy)
@@ -503,11 +503,12 @@
     * isNotEmpty
     * isOnlyDigits
     * isNotOnlyDigits
-    * isInteger
+    * isInteger    
     * isOnlyLetters
     * isValidANSIDate
     * isValidANSITime
     * isValidEmail
+    * isValidFloat    
     * isValidImage
     * isValidImageURL
     * isValidPhone
@@ -588,11 +589,15 @@
     Takes an integer argument and when called as a validator, checks that the
     field being validated is a power of the integer.
 
-``IsValidFloat``
+``IsValidDecimal``
     Takes a maximum number of digits and number of decimal places (in that
-    order) and validates whether the field is a float with less than the
-    maximum number of digits and decimal place.
+    order) and validates whether the field is a decimal with no more than the
+    maximum number of digits and decimal places.
 
+``IsValidFloat``
+    Takes a string argument and validates whether it can be converted to a
+    float.
+
 ``MatchesRegularExpression``
     Takes a regular expression (a string) as a parameter and validates the
     field value against it.
