diff -r 7dfb4f5c1bb0 django/db/backends/__init__.py
--- a/django/db/backends/__init__.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/django/db/backends/__init__.py	Mon Jul 07 13:37:17 2008 -0400
@@ -4,6 +4,8 @@ except ImportError:
 except ImportError:
     # Import copy of _thread_local.py from Python 2.4
     from django.utils._threading_local import local
+
+from django.db.backends import util
 
 class BaseDatabaseWrapper(local):
     """
@@ -36,23 +38,21 @@ class BaseDatabaseWrapper(local):
         return cursor
 
     def make_debug_cursor(self, cursor):
-        from django.db.backends import util
         return util.CursorDebugWrapper(cursor, self)
 
 class BaseDatabaseFeatures(object):
     allows_group_by_ordinal = True
     inline_fk_references = True
-    needs_datetime_string_cast = True
+    needs_datetime_string_cast = True # uses
+                                      # django.db.backend.utils.typecast_timetamp
+                                      # on returned values from dates()?
     supports_constraints = True
     supports_tablespaces = False
     uses_case_insensitive_names = False
     uses_custom_query_class = False
     empty_fetchmany_value = []
     update_can_self_select = True
-    supports_usecs = True
-    time_field_needs_date = False
     interprets_empty_strings_as_nulls = False
-    date_field_supports_time_value = True
 
 class BaseDatabaseOperations(object):
     """
@@ -272,3 +272,64 @@ class BaseDatabaseOperations(object):
         """Prepares a value for use in a LIKE query."""
         from django.utils.encoding import smart_unicode
         return smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
+
+    def value_to_db_date(self, value):
+        """
+        Transform a date value to an object compatible with what is expected
+        by the backend driver for date columns.
+        """
+        if value is None:
+            return None
+        return value.strftime('%Y-%m-%d')
+
+    def value_to_db_datetime(self, value):
+        """
+        Transform a datetime value to an object compatible with what is expected
+        by the backend driver for date columns.
+        """
+        if value is None:
+            return None
+        return unicode(value) # XXX: Why not just str(value)?
+
+    def value_to_db_time(self, value):
+        """
+        Transform a datetime value to an object compatible with what is expected
+        by the backend driver for date columns.
+        """
+        if value is None:
+            return None
+        return unicode(value) # XXX: Why not just str(value)?
+
+    def value_to_db_decimal(self, value, max_digits, decimal_places):
+        """
+        Transform a decimal.Decimal value to an object compatible with what is
+        expected by the backend driver for decimal (numeric) columns.
+        """
+        if value is None:
+            return None
+        return util.format_number(value, max_digits, decimal_places)
+
+    def year_lookup_bounds(self, value):
+        """
+        Returns a two-elements list with the lower and upper bound to be used
+        with a BETWEEN operator to query a field value using a year lookup
+
+        `value` is an int, containing the looked-up year.
+        """
+        first = '%s-01-01 00:00:00'
+        second = '%s-12-31 23:59:59.999999'
+        return [first % value, second % value]
+
+    def year_lookup_bounds_for_date_field(self, value):
+        """
+        Returns a two-elements list with the lower and upper bound to be used
+        with a BETWEEN operator to query a DateField value using a year lookup
+
+        `value` is an int, containing the looked-up year.
+
+        By default, it just calls `self.year_lookup_bounds`. Some backends need
+        this hook because on their DB date fields can't be compared to values
+        which include a time part.
+        """
+        return self.year_lookup_bounds(value)
+
diff -r 7dfb4f5c1bb0 django/db/backends/mysql/base.py
--- a/django/db/backends/mysql/base.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/django/db/backends/mysql/base.py	Mon Jul 07 13:37:17 2008 -0400
@@ -63,7 +63,6 @@ class DatabaseFeatures(BaseDatabaseFeatu
     inline_fk_references = False
     empty_fetchmany_value = ()
     update_can_self_select = False
-    supports_usecs = False
 
 class DatabaseOperations(BaseDatabaseOperations):
     def date_extract_sql(self, lookup_type, field_name):
@@ -130,6 +129,26 @@ class DatabaseOperations(BaseDatabaseOpe
             return sql
         else:
             return []
+
+    def value_to_db_datetime(self, value):
+        # MySQL doesn't support microseconds
+        if value is None:
+            return None
+        # XXX: Why not just str(value)?
+        return unicode(value.replace(microsecond=0))
+
+    def value_to_db_time(self, value):
+        # MySQL doesn't support microseconds
+        if value is None:
+            return None
+        # XXX: Why not just str(value)?
+        return unicode(value.replace(microsecond=0))
+
+    def year_lookup_bounds(self, value):
+        # Again, no microseconds
+        first = '%s-01-01 00:00:00'
+        second = '%s-12-31 23:59:59.99'
+        return [first % value, second % value]
 
 class DatabaseWrapper(BaseDatabaseWrapper):
     features = DatabaseFeatures()
diff -r 7dfb4f5c1bb0 django/db/backends/mysql_old/base.py
--- a/django/db/backends/mysql_old/base.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/django/db/backends/mysql_old/base.py	Mon Jul 07 13:37:17 2008 -0400
@@ -67,7 +67,6 @@ class DatabaseFeatures(BaseDatabaseFeatu
     inline_fk_references = False
     empty_fetchmany_value = ()
     update_can_self_select = False
-    supports_usecs = False
 
 class DatabaseOperations(BaseDatabaseOperations):
     def date_extract_sql(self, lookup_type, field_name):
@@ -134,6 +133,28 @@ class DatabaseOperations(BaseDatabaseOpe
             return sql
         else:
             return []
+
+    def value_to_db_datetime(self, value):
+        # MySQL doesn't support microseconds
+        if value is None:
+            return None
+        # XXX: Why not just str(value)?
+        return unicode(value.replace(microsecond=0))
+
+    def value_to_db_time(self, value):
+        # MySQL doesn't support microseconds
+        if value is None:
+            return None
+        # XXX: Why not just str(value)?
+        return unicode(value.replace(microsecond=0))
+
+
+    def year_lookup_bounds(self, value):
+        # Again, no microseconds
+        first = '%s-01-01 00:00:00'
+        second = '%s-12-31 23:59:59.99'
+        return [first % value, second % value]
+
 
 class DatabaseWrapper(BaseDatabaseWrapper):
     features = DatabaseFeatures()
diff -r 7dfb4f5c1bb0 django/db/backends/oracle/base.py
--- a/django/db/backends/oracle/base.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/django/db/backends/oracle/base.py	Mon Jul 07 13:37:17 2008 -0400
@@ -5,6 +5,8 @@ Requires cx_Oracle: http://www.python.ne
 """
 
 import os
+import datetime
+import time
 
 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
 from django.db.backends.oracle import query
@@ -29,9 +31,7 @@ class DatabaseFeatures(BaseDatabaseFeatu
     supports_tablespaces = True
     uses_case_insensitive_names = True
     uses_custom_query_class = True
-    time_field_needs_date = True
     interprets_empty_strings_as_nulls = True
-    date_field_supports_time_value = False
 
 class DatabaseOperations(BaseDatabaseOperations):
     def autoinc_sql(self, table, column):
@@ -185,6 +185,21 @@ class DatabaseOperations(BaseDatabaseOpe
 
     def tablespace_sql(self, tablespace, inline=False):
         return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), self.quote_name(tablespace))
+
+    def value_to_db_time(self, value):
+        if value is None:
+            return None
+        if isinstance(value, basestring):
+            return datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6]))
+        return datetime.datetime(1900, 1, 1, value.hour, value.minute,
+                                 value.second, value.microsecond)
+
+    def year_lookup_bounds_for_date_field(self, value):
+        first = '%s-01-01'
+        second = '%s-12-31'
+        return [first % value, second % value]
+
+
 
 class DatabaseWrapper(BaseDatabaseWrapper):
     features = DatabaseFeatures()
diff -r 7dfb4f5c1bb0 django/db/backends/sqlite3/base.py
--- a/django/db/backends/sqlite3/base.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/django/db/backends/sqlite3/base.py	Mon Jul 07 13:37:17 2008 -0400
@@ -79,6 +79,12 @@ class DatabaseOperations(BaseDatabaseOpe
         # sql_flush() implementations). Just return SQL at this point
         return sql
 
+    def year_lookup_bounds(self, value):
+        first = '%s-01-01'
+        second = '%s-12-31 23:59:59.999999'
+        return [first % value, second % value]
+
+
 class DatabaseWrapper(BaseDatabaseWrapper):
     features = DatabaseFeatures()
     ops = DatabaseOperations()
@@ -151,7 +157,7 @@ def _sqlite_extract(lookup_type, dt):
         dt = util.typecast_timestamp(dt)
     except (ValueError, TypeError):
         return None
-    return str(getattr(dt, lookup_type))
+    return getattr(dt, lookup_type)
 
 def _sqlite_date_trunc(lookup_type, dt):
     try:
diff -r 7dfb4f5c1bb0 django/db/backends/util.py
--- a/django/db/backends/util.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/django/db/backends/util.py	Mon Jul 07 13:37:17 2008 -0400
@@ -117,3 +117,10 @@ def truncate_name(name, length=None):
     hash = md5.md5(name).hexdigest()[:4]
 
     return '%s%s' % (name[:length-4], hash)
+
+def format_number(value, max_digits, decimal_places):
+    """
+    Formats a number into a string with the requisite number of digits and
+    decimal places.
+    """
+    return u"%.*f" % (decimal_places, value)
diff -r 7dfb4f5c1bb0 django/db/models/base.py
--- a/django/db/models/base.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/django/db/models/base.py	Mon Jul 07 13:37:17 2008 -0400
@@ -297,7 +297,7 @@ class Model(object):
 
         # If we are in a raw save, save the object exactly as presented.
         # That means that we don't try to be smart about saving attributes
-        # that might have come from the parent class - we just save the 
+        # that might have come from the parent class - we just save the
         # attributes we have been given to the class we have been given.
         if not raw:
             for parent, field in meta.parents.items():
@@ -305,7 +305,7 @@ class Model(object):
                 setattr(self, field.attname, self._get_pk_val(parent._meta))
 
         non_pks = [f for f in meta.local_fields if not f.primary_key]
-            
+
         # First, try an UPDATE. If that doesn't update anything, do an INSERT.
         pk_val = self._get_pk_val(meta)
         # Note: the comparison with '' is required for compatibility with
diff -r 7dfb4f5c1bb0 django/db/models/fields/__init__.py
--- a/django/db/models/fields/__init__.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/django/db/models/fields/__init__.py	Mon Jul 07 13:37:17 2008 -0400
@@ -252,19 +252,12 @@ class Field(object):
                 value = int(value)
             except ValueError:
                 raise ValueError("The __year lookup type requires an integer argument")
-            if settings.DATABASE_ENGINE == 'sqlite3':
-                first = '%s-01-01'
-                second = '%s-12-31 23:59:59.999999'
-            elif not connection.features.date_field_supports_time_value and self.get_internal_type() == 'DateField':
-                first = '%s-01-01'
-                second = '%s-12-31'
-            elif not connection.features.supports_usecs:
-                first = '%s-01-01 00:00:00'
-                second = '%s-12-31 23:59:59.99'
+
+            if self.get_internal_type() == 'DateField':
+                return connection.ops.year_lookup_bounds_for_date_field(value)
             else:
-                first = '%s-01-01 00:00:00'
-                second = '%s-12-31 23:59:59.999999'
-            return [first % value, second % value]
+                return connection.ops.year_lookup_bounds(value)
+
         raise TypeError("Field has invalid lookup: %s" % lookup_type)
 
     def has_default(self):
@@ -453,6 +446,18 @@ class AutoField(Field):
         except (TypeError, ValueError):
             raise validators.ValidationError, _("This value must be an integer.")
 
+    def get_db_prep_save(self, value):
+        if value is None:
+            return None
+        return int(value)
+
+    def get_db_prep_lookup(self, lookup_type, value):
+        if lookup_type == 'range':
+            value = [int(v) for v in value]
+        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
+            value = int(value)
+        return Field.get_db_prep_lookup(self, lookup_type, value)
+
     def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
         if not rel:
             return [] # Don't add a FormField unless it's in a related context.
@@ -491,6 +496,16 @@ class BooleanField(Field):
         if value in ('t', 'True', '1'): return True
         if value in ('f', 'False', '0'): return False
         raise validators.ValidationError, _("This value must be either True or False.")
+
+    def get_db_prep_save(self, value):
+        if value is None:
+            return None
+        return bool(value)
+
+    def get_db_prep_lookup(self, lookup_type, value):
+        if lookup_type == 'exact' and value is not None:
+            value = bool(value)
+        return Field.get_db_prep_lookup(self, lookup_type, value)
 
     def get_manipulator_field_objs(self):
         return [oldforms.CheckboxField]
@@ -554,12 +569,12 @@ class DateField(Field):
             raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.')
 
     def get_db_prep_lookup(self, lookup_type, value):
+        value_to_db_date = connection.ops.value_to_db_date
         if lookup_type == 'range':
-            value = [smart_unicode(v) for v in value]
-        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte') and hasattr(value, 'strftime'):
-            value = value.strftime('%Y-%m-%d')
-        else:
-            value = smart_unicode(value)
+            value = [value_to_db_date(self.to_python(v)) for v in value]
+        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
+            # Lookups with a date argument
+            value = value_to_db_date(self.to_python(value))
         return Field.get_db_prep_lookup(self, lookup_type, value)
 
     def pre_save(self, model_instance, add):
@@ -586,15 +601,8 @@ class DateField(Field):
             return self.editable or self.auto_now or self.auto_now_add
 
     def get_db_prep_save(self, value):
-        # Casts dates into string format for entry into database.
-        if value is not None:
-            try:
-                value = value.strftime('%Y-%m-%d')
-            except AttributeError:
-                # If value is already a string it won't have a strftime method,
-                # so we'll just let it pass through.
-                pass
-        return Field.get_db_prep_save(self, value)
+        # Casts dates into the format expected by the backend
+        return connection.ops.value_to_db_date(self.to_python(value))
 
     def get_manipulator_field_objs(self):
         return [oldforms.DateField]
@@ -619,32 +627,44 @@ class DateTimeField(DateField):
             return value
         if isinstance(value, datetime.date):
             return datetime.datetime(value.year, value.month, value.day)
+
+        # Attempt to parse a datetime:
+        value = smart_str(value)
+        # split usecs, because they are not recognized by strptime.
+        if '.' in value:
+            try:
+                value, usecs = value.split('.')
+                usecs = int(usecs)
+            except ValueError:
+                raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[ss[.uuuuuu]] format.')
+        else:
+            usecs = 0
+        kwargs = {'microsecond': usecs}
         try: # Seconds are optional, so try converting seconds first.
-            return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6])
+            return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6],
+                                     **kwargs)
+
         except ValueError:
             try: # Try without seconds.
-                return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M')[:5])
+                return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M')[:5],
+                                         **kwargs)
             except ValueError: # Try without hour/minutes/seconds.
                 try:
-                    return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3])
+                    return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3],
+                                             **kwargs)
                 except ValueError:
-                    raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
+                    raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[ss[.uuuuuu]] format.')
 
     def get_db_prep_save(self, value):
-        # Casts dates into string format for entry into database.
-        if value is not None:
-            # MySQL will throw a warning if microseconds are given, because it
-            # doesn't support microseconds.
-            if not connection.features.supports_usecs and hasattr(value, 'microsecond'):
-                value = value.replace(microsecond=0)
-            value = smart_unicode(value)
-        return Field.get_db_prep_save(self, value)
+        # Casts dates into the format expected by the backend
+        return connection.ops.value_to_db_datetime(self.to_python(value))
 
     def get_db_prep_lookup(self, lookup_type, value):
+        value_to_db_datetime = connection.ops.value_to_db_datetime
         if lookup_type == 'range':
-            value = [smart_unicode(v) for v in value]
-        else:
-            value = smart_unicode(value)
+            value = [value_to_db_datetime(self.to_python(v)) for v in value]
+        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
+            value = value_to_db_datetime(self.to_python(value))
         return Field.get_db_prep_lookup(self, lookup_type, value)
 
     def get_manipulator_field_objs(self):
@@ -705,25 +725,28 @@ class DecimalField(Field):
         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 u"%.*f" % (self.decimal_places, value)
+        # Method moved to django.db.backends.util.
+        #
+        # It is preserved because it is used by the oracle backend
+        # (django.db.backends.oracle.query), and also for
+        # backwards-compatibility with any external code which may have used
+        # this method.
+        from django.db.backends import util
+        return util.format_number(value, self.max_digits, self.decimal_places)
 
     def get_db_prep_save(self, value):
-        value = self._format(value)
-        return super(DecimalField, self).get_db_prep_save(value)
+        return connection.ops.value_to_db_decimal(value, self.max_digits,
+                                                  self.decimal_places)
 
     def get_db_prep_lookup(self, lookup_type, value):
+        value_to_db_decimal = connection.ops.value_to_db_decimal
         if lookup_type == 'range':
-            value = [self._format(v) for v in value]
+            value = [value_to_db_decimal(v, self.max_digits,
+                                         self.decimal_places)
+                     for v in value]
         else:
-            value = self._format(value)
+            value = value_to_db_decimal(value, self.max_digits,
+                                        self.decimal_places)
         return super(DecimalField, self).get_db_prep_lookup(lookup_type, value)
 
     def get_manipulator_field_objs(self):
@@ -898,6 +921,18 @@ class FloatField(Field):
 class FloatField(Field):
     empty_strings_allowed = False
 
+    def get_db_prep_save(self, value):
+        if value is None:
+            return None
+        return float(value)
+
+    def get_db_prep_lookup(self, lookup_type, value):
+        if lookup_type == 'range':
+            value = [float(v) for v in value]
+        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
+            value = float(value)
+        return Field.get_db_prep_lookup(self, lookup_type, value)
+
     def get_manipulator_field_objs(self):
         return [oldforms.FloatField]
 
@@ -948,6 +983,18 @@ class ImageField(FileField):
 
 class IntegerField(Field):
     empty_strings_allowed = False
+    def get_db_prep_save(self, value):
+        if value is None:
+            return None
+        return int(value)
+
+    def get_db_prep_lookup(self, lookup_type, value):
+        if lookup_type == 'range':
+            value = [int(v) for v in value]
+        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
+            value = int(value)
+        return Field.get_db_prep_lookup(self, lookup_type, value)
+
     def get_manipulator_field_objs(self):
         return [oldforms.IntegerField]
 
@@ -995,6 +1042,17 @@ class NullBooleanField(Field):
         if value in ('f', 'False', '0'): return False
         raise validators.ValidationError, _("This value must be either None, True or False.")
 
+    def get_db_prep_save(self, value):
+        if value is None:
+            return None
+        return bool(value)
+
+    def get_db_prep_lookup(self, lookup_type, value):
+        if lookup_type == 'exact' and value is not None:
+            value = bool(value)
+        return Field.get_db_prep_lookup(self, lookup_type, value)
+
+
     def get_manipulator_field_objs(self):
         return [oldforms.NullBooleanField]
 
@@ -1003,7 +1061,7 @@ class NullBooleanField(Field):
         defaults.update(kwargs)
         return super(NullBooleanField, self).formfield(**defaults)
 
-class PhoneNumberField(IntegerField):
+class PhoneNumberField(Field):
     def get_manipulator_field_objs(self):
         return [oldforms.PhoneNumberField]
 
@@ -1085,19 +1143,41 @@ class TimeField(Field):
     def get_internal_type(self):
         return "TimeField"
 
+    def to_python(self, value):
+        if value is None:
+            return None
+        if isinstance(value, datetime.time):
+            return value
+
+        # Attempt to parse a datetime:
+        value = smart_str(value)
+        # split usecs, because they are not recognized by strptime.
+        if '.' in value:
+            try:
+                value, usecs = value.split('.')
+                usecs = int(usecs)
+            except ValueError:
+                raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.')
+        else:
+            usecs = 0
+        kwargs = {'microsecond': usecs}
+
+        try: # Seconds are optional, so try converting seconds first.
+            return datetime.time(*time.strptime(value, '%H:%M:%S')[3:6],
+                                 **kwargs)
+        except ValueError:
+            try: # Try without seconds.
+                return datetime.datetime(*time.strptime(value, '%H:%M')[:5],
+                                         **kwargs)
+            except ValueError:
+                raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.')
+
     def get_db_prep_lookup(self, lookup_type, value):
-        if connection.features.time_field_needs_date:
-            # Oracle requires a date in order to parse.
-            def prep(value):
-                if isinstance(value, datetime.time):
-                    value = datetime.datetime.combine(datetime.date(1900, 1, 1), value)
-                return smart_unicode(value)
-        else:
-            prep = smart_unicode
+        value_to_db_time = connection.ops.value_to_db_time
         if lookup_type == 'range':
-            value = [prep(v) for v in value]
-        else:
-            value = prep(value)
+            value = [value_to_db_time(self.to_python(v)) for v in value]
+        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
+            value = value_to_db_time(self.to_python(value))
         return Field.get_db_prep_lookup(self, lookup_type, value)
 
     def pre_save(self, model_instance, add):
@@ -1109,22 +1189,8 @@ class TimeField(Field):
             return super(TimeField, self).pre_save(model_instance, add)
 
     def get_db_prep_save(self, value):
-        # Casts dates into string format for entry into database.
-        if value is not None:
-            # MySQL will throw a warning if microseconds are given, because it
-            # doesn't support microseconds.
-            if not connection.features.supports_usecs and hasattr(value, 'microsecond'):
-                value = value.replace(microsecond=0)
-            if connection.features.time_field_needs_date:
-                # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field.
-                if isinstance(value, datetime.time):
-                    value = datetime.datetime(1900, 1, 1, value.hour, value.minute,
-                                              value.second, value.microsecond)
-                elif isinstance(value, basestring):
-                    value = datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6]))
-            else:
-                value = smart_unicode(value)
-        return Field.get_db_prep_save(self, value)
+        # Casts times into the format expected by the backend
+        return connection.ops.value_to_db_time(self.to_python(value))
 
     def get_manipulator_field_objs(self):
         return [oldforms.TimeField]
diff -r 7dfb4f5c1bb0 tests/modeltests/custom_methods/models.py
--- a/tests/modeltests/custom_methods/models.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/tests/modeltests/custom_methods/models.py	Mon Jul 07 13:37:17 2008 -0400
@@ -31,7 +31,8 @@ class Article(models.Model):
             SELECT id, headline, pub_date
             FROM custom_methods_article
             WHERE pub_date = %s
-                AND id != %s""", [str(self.pub_date), self.id])
+                AND id != %s""", [connection.ops.value_to_db_date(self.pub_date),
+                                  self.id])
         # The asterisk in "(*row)" tells Python to expand the list into
         # positional arguments to Article().
         return [self.__class__(*row) for row in cursor.fetchall()]
diff -r 7dfb4f5c1bb0 tests/regressiontests/model_fields/tests.py
--- a/tests/regressiontests/model_fields/tests.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/tests/regressiontests/model_fields/tests.py	Mon Jul 07 13:37:17 2008 -0400
@@ -20,16 +20,26 @@ ValidationError: [u'This value must be a
 >>> x = f.to_python(2)
 >>> y = f.to_python('2.6')
 
->>> f.get_db_prep_save(x)
+>>> f._format(x)
 u'2.0'
->>> f.get_db_prep_save(y)
+>>> f._format(y)
 u'2.6'
->>> f.get_db_prep_save(None)
->>> f.get_db_prep_lookup('exact', x)
-[u'2.0']
->>> f.get_db_prep_lookup('exact', y)
-[u'2.6']
+>>> f._format(None)
 >>> f.get_db_prep_lookup('exact', None)
 [None]
 
+# DateTimeField and TimeField to_python should support usecs:
+>>> f = DateTimeField()
+>>> f.to_python('2001-01-02 03:04:05.000006')
+datetime.datetime(2001, 1, 2, 3, 4, 5, 6)
+>>> f.to_python('2001-01-02 03:04:05.999999')
+datetime.datetime(2001, 1, 2, 3, 4, 5, 999999)
+
+>>> f = TimeField()
+>>> f.to_python('01:02:03.000004')
+datetime.time(1, 2, 3, 4)
+>>> f.to_python('01:02:03.999999')
+datetime.time(1, 2, 3, 999999)
+
+
 """
diff -r 7dfb4f5c1bb0 tests/regressiontests/model_regress/models.py
--- a/tests/regressiontests/model_regress/models.py	Thu Jul 03 14:21:54 2008 -0500
+++ b/tests/regressiontests/model_regress/models.py	Mon Jul 07 13:37:17 2008 -0400
@@ -28,6 +28,9 @@ class Movie(models.Model):
 
 class Party(models.Model):
     when = models.DateField()
+
+class Event(models.Model):
+    when = models.DateTimeField()
 
 __test__ = {'API_TESTS': """
 (NOTE: Part of the regression test here is merely parsing the model
@@ -68,5 +71,21 @@ 5000
 >>> [p.when for p in Party.objects.filter(when__year = 1998)]
 [datetime.date(1998, 12, 31)]
 
+# Check that get_next_by_FIELD and get_previous_by_FIELD don't crash when we
+# have usecs values stored on the database
+#
+# [It crashed after the Field.get_db_prep_* refactor, because on most backends
+#  DateTimeFields supports usecs, but DateTimeField.to_python didn't recognize
+#  them. (Note that Model._get_next_or_previous_by_FIELD coerces values to
+#  strings)]
+#
+>>> e = Event.objects.create(when = datetime.datetime(2000, 1, 1, 16, 0, 0))
+>>> e = Event.objects.create(when = datetime.datetime(2000, 1, 1, 6, 1, 1))
+>>> e = Event.objects.create(when = datetime.datetime(2000, 1, 1, 13, 1, 1))
+>>> e = Event.objects.create(when = datetime.datetime(2000, 1, 1, 12, 0, 20, 24))
+>>> e.get_next_by_when().when
+datetime.datetime(2000, 1, 1, 13, 1, 1)
+>>> e.get_previous_by_when().when
+datetime.datetime(2000, 1, 1, 6, 1, 1)
 """
 }
