Ticket #7560: get_db_prep_refactor-4.patch

File get_db_prep_refactor-4.patch, 28.9 KB (added by Leo Soto M., 16 years ago)

Also fixes to_python on Time and DateTime fields. Includes tests for this addition.

  • django/db/backends/__init__.py

    diff -r 7dfb4f5c1bb0 django/db/backends/__init__.py
    a b except ImportError:  
    44except ImportError:
    55    # Import copy of _thread_local.py from Python 2.4
    66    from django.utils._threading_local import local
     7
     8from django.db.backends import util
    79
    810class BaseDatabaseWrapper(local):
    911    """
    class BaseDatabaseWrapper(local):  
    3638        return cursor
    3739
    3840    def make_debug_cursor(self, cursor):
    39         from django.db.backends import util
    4041        return util.CursorDebugWrapper(cursor, self)
    4142
    4243class BaseDatabaseFeatures(object):
    4344    allows_group_by_ordinal = True
    4445    inline_fk_references = True
    45     needs_datetime_string_cast = True
     46    needs_datetime_string_cast = True # uses
     47                                      # django.db.backend.utils.typecast_timetamp
     48                                      # on returned values from dates()?
    4649    supports_constraints = True
    4750    supports_tablespaces = False
    4851    uses_case_insensitive_names = False
    4952    uses_custom_query_class = False
    5053    empty_fetchmany_value = []
    5154    update_can_self_select = True
    52     supports_usecs = True
    53     time_field_needs_date = False
    5455    interprets_empty_strings_as_nulls = False
    55     date_field_supports_time_value = True
    5656
    5757class BaseDatabaseOperations(object):
    5858    """
    class BaseDatabaseOperations(object):  
    272272        """Prepares a value for use in a LIKE query."""
    273273        from django.utils.encoding import smart_unicode
    274274        return smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
     275
     276    def value_to_db_date(self, value):
     277        """
     278        Transform a date value to an object compatible with what is expected
     279        by the backend driver for date columns.
     280        """
     281        if value is None:
     282            return None
     283        return value.strftime('%Y-%m-%d')
     284
     285    def value_to_db_datetime(self, value):
     286        """
     287        Transform a datetime value to an object compatible with what is expected
     288        by the backend driver for date columns.
     289        """
     290        if value is None:
     291            return None
     292        return unicode(value) # XXX: Why not just str(value)?
     293
     294    def value_to_db_time(self, value):
     295        """
     296        Transform a datetime value to an object compatible with what is expected
     297        by the backend driver for date columns.
     298        """
     299        if value is None:
     300            return None
     301        return unicode(value) # XXX: Why not just str(value)?
     302
     303    def value_to_db_decimal(self, value, max_digits, decimal_places):
     304        """
     305        Transform a decimal.Decimal value to an object compatible with what is
     306        expected by the backend driver for decimal (numeric) columns.
     307        """
     308        if value is None:
     309            return None
     310        return util.format_number(value, max_digits, decimal_places)
     311
     312    def year_lookup_bounds(self, value):
     313        """
     314        Returns a two-elements list with the lower and upper bound to be used
     315        with a BETWEEN operator to query a field value using a year lookup
     316
     317        `value` is an int, containing the looked-up year.
     318        """
     319        first = '%s-01-01 00:00:00'
     320        second = '%s-12-31 23:59:59.999999'
     321        return [first % value, second % value]
     322
     323    def year_lookup_bounds_for_date_field(self, value):
     324        """
     325        Returns a two-elements list with the lower and upper bound to be used
     326        with a BETWEEN operator to query a DateField value using a year lookup
     327
     328        `value` is an int, containing the looked-up year.
     329
     330        By default, it just calls `self.year_lookup_bounds`. Some backends need
     331        this hook because on their DB date fields can't be compared to values
     332        which include a time part.
     333        """
     334        return self.year_lookup_bounds(value)
     335
  • django/db/backends/mysql/base.py

    diff -r 7dfb4f5c1bb0 django/db/backends/mysql/base.py
    a b class DatabaseFeatures(BaseDatabaseFeatu  
    6363    inline_fk_references = False
    6464    empty_fetchmany_value = ()
    6565    update_can_self_select = False
    66     supports_usecs = False
    6766
    6867class DatabaseOperations(BaseDatabaseOperations):
    6968    def date_extract_sql(self, lookup_type, field_name):
    class DatabaseOperations(BaseDatabaseOpe  
    130129            return sql
    131130        else:
    132131            return []
     132
     133    def value_to_db_datetime(self, value):
     134        # MySQL doesn't support microseconds
     135        if value is None:
     136            return None
     137        # XXX: Why not just str(value)?
     138        return unicode(value.replace(microsecond=0))
     139
     140    def value_to_db_time(self, value):
     141        # MySQL doesn't support microseconds
     142        if value is None:
     143            return None
     144        # XXX: Why not just str(value)?
     145        return unicode(value.replace(microsecond=0))
     146
     147    def year_lookup_bounds(self, value):
     148        # Again, no microseconds
     149        first = '%s-01-01 00:00:00'
     150        second = '%s-12-31 23:59:59.99'
     151        return [first % value, second % value]
    133152
    134153class DatabaseWrapper(BaseDatabaseWrapper):
    135154    features = DatabaseFeatures()
  • django/db/backends/mysql_old/base.py

    diff -r 7dfb4f5c1bb0 django/db/backends/mysql_old/base.py
    a b class DatabaseFeatures(BaseDatabaseFeatu  
    6767    inline_fk_references = False
    6868    empty_fetchmany_value = ()
    6969    update_can_self_select = False
    70     supports_usecs = False
    7170
    7271class DatabaseOperations(BaseDatabaseOperations):
    7372    def date_extract_sql(self, lookup_type, field_name):
    class DatabaseOperations(BaseDatabaseOpe  
    134133            return sql
    135134        else:
    136135            return []
     136
     137    def value_to_db_datetime(self, value):
     138        # MySQL doesn't support microseconds
     139        if value is None:
     140            return None
     141        # XXX: Why not just str(value)?
     142        return unicode(value.replace(microsecond=0))
     143
     144    def value_to_db_time(self, value):
     145        # MySQL doesn't support microseconds
     146        if value is None:
     147            return None
     148        # XXX: Why not just str(value)?
     149        return unicode(value.replace(microsecond=0))
     150
     151
     152    def year_lookup_bounds(self, value):
     153        # Again, no microseconds
     154        first = '%s-01-01 00:00:00'
     155        second = '%s-12-31 23:59:59.99'
     156        return [first % value, second % value]
     157
    137158
    138159class DatabaseWrapper(BaseDatabaseWrapper):
    139160    features = DatabaseFeatures()
  • django/db/backends/oracle/base.py

    diff -r 7dfb4f5c1bb0 django/db/backends/oracle/base.py
    a b Requires cx_Oracle: http://www.python.ne  
    55"""
    66
    77import os
     8import datetime
     9import time
    810
    911from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
    1012from django.db.backends.oracle import query
    class DatabaseFeatures(BaseDatabaseFeatu  
    2931    supports_tablespaces = True
    3032    uses_case_insensitive_names = True
    3133    uses_custom_query_class = True
    32     time_field_needs_date = True
    3334    interprets_empty_strings_as_nulls = True
    34     date_field_supports_time_value = False
    3535
    3636class DatabaseOperations(BaseDatabaseOperations):
    3737    def autoinc_sql(self, table, column):
    class DatabaseOperations(BaseDatabaseOpe  
    185185
    186186    def tablespace_sql(self, tablespace, inline=False):
    187187        return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), self.quote_name(tablespace))
     188
     189    def value_to_db_time(self, value):
     190        if value is None:
     191            return None
     192        if isinstance(value, basestring):
     193            return datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6]))
     194        return datetime.datetime(1900, 1, 1, value.hour, value.minute,
     195                                 value.second, value.microsecond)
     196
     197    def year_lookup_bounds_for_date_field(self, value):
     198        first = '%s-01-01'
     199        second = '%s-12-31'
     200        return [first % value, second % value]
     201
     202
    188203
    189204class DatabaseWrapper(BaseDatabaseWrapper):
    190205    features = DatabaseFeatures()
  • django/db/backends/sqlite3/base.py

    diff -r 7dfb4f5c1bb0 django/db/backends/sqlite3/base.py
    a b class DatabaseOperations(BaseDatabaseOpe  
    7979        # sql_flush() implementations). Just return SQL at this point
    8080        return sql
    8181
     82    def year_lookup_bounds(self, value):
     83        first = '%s-01-01'
     84        second = '%s-12-31 23:59:59.999999'
     85        return [first % value, second % value]
     86
     87
    8288class DatabaseWrapper(BaseDatabaseWrapper):
    8389    features = DatabaseFeatures()
    8490    ops = DatabaseOperations()
    def _sqlite_extract(lookup_type, dt):  
    151157        dt = util.typecast_timestamp(dt)
    152158    except (ValueError, TypeError):
    153159        return None
    154     return str(getattr(dt, lookup_type))
     160    return getattr(dt, lookup_type)
    155161
    156162def _sqlite_date_trunc(lookup_type, dt):
    157163    try:
  • django/db/backends/util.py

    diff -r 7dfb4f5c1bb0 django/db/backends/util.py
    a b def truncate_name(name, length=None):  
    117117    hash = md5.md5(name).hexdigest()[:4]
    118118
    119119    return '%s%s' % (name[:length-4], hash)
     120
     121def format_number(value, max_digits, decimal_places):
     122    """
     123    Formats a number into a string with the requisite number of digits and
     124    decimal places.
     125    """
     126    return u"%.*f" % (decimal_places, value)
  • django/db/models/base.py

    diff -r 7dfb4f5c1bb0 django/db/models/base.py
    a b class Model(object):  
    297297
    298298        # If we are in a raw save, save the object exactly as presented.
    299299        # That means that we don't try to be smart about saving attributes
    300         # that might have come from the parent class - we just save the 
     300        # that might have come from the parent class - we just save the
    301301        # attributes we have been given to the class we have been given.
    302302        if not raw:
    303303            for parent, field in meta.parents.items():
    class Model(object):  
    305305                setattr(self, field.attname, self._get_pk_val(parent._meta))
    306306
    307307        non_pks = [f for f in meta.local_fields if not f.primary_key]
    308            
     308
    309309        # First, try an UPDATE. If that doesn't update anything, do an INSERT.
    310310        pk_val = self._get_pk_val(meta)
    311311        # Note: the comparison with '' is required for compatibility with
  • django/db/models/fields/__init__.py

    diff -r 7dfb4f5c1bb0 django/db/models/fields/__init__.py
    a b class Field(object):  
    252252                value = int(value)
    253253            except ValueError:
    254254                raise ValueError("The __year lookup type requires an integer argument")
    255             if settings.DATABASE_ENGINE == 'sqlite3':
    256                 first = '%s-01-01'
    257                 second = '%s-12-31 23:59:59.999999'
    258             elif not connection.features.date_field_supports_time_value and self.get_internal_type() == 'DateField':
    259                 first = '%s-01-01'
    260                 second = '%s-12-31'
    261             elif not connection.features.supports_usecs:
    262                 first = '%s-01-01 00:00:00'
    263                 second = '%s-12-31 23:59:59.99'
     255
     256            if self.get_internal_type() == 'DateField':
     257                return connection.ops.year_lookup_bounds_for_date_field(value)
    264258            else:
    265                 first = '%s-01-01 00:00:00'
    266                 second = '%s-12-31 23:59:59.999999'
    267             return [first % value, second % value]
     259                return connection.ops.year_lookup_bounds(value)
     260
    268261        raise TypeError("Field has invalid lookup: %s" % lookup_type)
    269262
    270263    def has_default(self):
    class AutoField(Field):  
    453446        except (TypeError, ValueError):
    454447            raise validators.ValidationError, _("This value must be an integer.")
    455448
     449    def get_db_prep_save(self, value):
     450        if value is None:
     451            return None
     452        return int(value)
     453
     454    def get_db_prep_lookup(self, lookup_type, value):
     455        if lookup_type == 'range':
     456            value = [int(v) for v in value]
     457        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     458            value = int(value)
     459        return Field.get_db_prep_lookup(self, lookup_type, value)
     460
    456461    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
    457462        if not rel:
    458463            return [] # Don't add a FormField unless it's in a related context.
    class BooleanField(Field):  
    491496        if value in ('t', 'True', '1'): return True
    492497        if value in ('f', 'False', '0'): return False
    493498        raise validators.ValidationError, _("This value must be either True or False.")
     499
     500    def get_db_prep_save(self, value):
     501        if value is None:
     502            return None
     503        return bool(value)
     504
     505    def get_db_prep_lookup(self, lookup_type, value):
     506        if lookup_type == 'exact' and value is not None:
     507            value = bool(value)
     508        return Field.get_db_prep_lookup(self, lookup_type, value)
    494509
    495510    def get_manipulator_field_objs(self):
    496511        return [oldforms.CheckboxField]
    class DateField(Field):  
    554569            raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.')
    555570
    556571    def get_db_prep_lookup(self, lookup_type, value):
     572        value_to_db_date = connection.ops.value_to_db_date
    557573        if lookup_type == 'range':
    558             value = [smart_unicode(v) for v in value]
    559         elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte') and hasattr(value, 'strftime'):
    560             value = value.strftime('%Y-%m-%d')
    561         else:
    562             value = smart_unicode(value)
     574            value = [value_to_db_date(self.to_python(v)) for v in value]
     575        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     576            # Lookups with a date argument
     577            value = value_to_db_date(self.to_python(value))
    563578        return Field.get_db_prep_lookup(self, lookup_type, value)
    564579
    565580    def pre_save(self, model_instance, add):
    class DateField(Field):  
    586601            return self.editable or self.auto_now or self.auto_now_add
    587602
    588603    def get_db_prep_save(self, value):
    589         # Casts dates into string format for entry into database.
    590         if value is not None:
    591             try:
    592                 value = value.strftime('%Y-%m-%d')
    593             except AttributeError:
    594                 # If value is already a string it won't have a strftime method,
    595                 # so we'll just let it pass through.
    596                 pass
    597         return Field.get_db_prep_save(self, value)
     604        # Casts dates into the format expected by the backend
     605        return connection.ops.value_to_db_date(self.to_python(value))
    598606
    599607    def get_manipulator_field_objs(self):
    600608        return [oldforms.DateField]
    class DateTimeField(DateField):  
    619627            return value
    620628        if isinstance(value, datetime.date):
    621629            return datetime.datetime(value.year, value.month, value.day)
     630
     631        # Attempt to parse a datetime:
     632        value = smart_str(value)
     633        # split usecs, because they are not recognized by strptime.
     634        if '.' in value:
     635            try:
     636                value, usecs = value.split('.')
     637                usecs = int(usecs)
     638            except ValueError:
     639                raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[ss[.uuuuuu]] format.')
     640        else:
     641            usecs = 0
     642        kwargs = {'microsecond': usecs}
    622643        try: # Seconds are optional, so try converting seconds first.
    623             return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6])
     644            return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6],
     645                                     **kwargs)
     646
    624647        except ValueError:
    625648            try: # Try without seconds.
    626                 return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M')[:5])
     649                return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M')[:5],
     650                                         **kwargs)
    627651            except ValueError: # Try without hour/minutes/seconds.
    628652                try:
    629                     return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3])
     653                    return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3],
     654                                             **kwargs)
    630655                except ValueError:
    631                     raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
     656                    raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[ss[.uuuuuu]] format.')
    632657
    633658    def get_db_prep_save(self, value):
    634         # Casts dates into string format for entry into database.
    635         if value is not None:
    636             # MySQL will throw a warning if microseconds are given, because it
    637             # doesn't support microseconds.
    638             if not connection.features.supports_usecs and hasattr(value, 'microsecond'):
    639                 value = value.replace(microsecond=0)
    640             value = smart_unicode(value)
    641         return Field.get_db_prep_save(self, value)
     659        # Casts dates into the format expected by the backend
     660        return connection.ops.value_to_db_datetime(self.to_python(value))
    642661
    643662    def get_db_prep_lookup(self, lookup_type, value):
     663        value_to_db_datetime = connection.ops.value_to_db_datetime
    644664        if lookup_type == 'range':
    645             value = [smart_unicode(v) for v in value]
    646         else:
    647             value = smart_unicode(value)
     665            value = [value_to_db_datetime(self.to_python(v)) for v in value]
     666        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     667            value = value_to_db_datetime(self.to_python(value))
    648668        return Field.get_db_prep_lookup(self, lookup_type, value)
    649669
    650670    def get_manipulator_field_objs(self):
    class DecimalField(Field):  
    705725        Formats a number into a string with the requisite number of digits and
    706726        decimal places.
    707727        """
    708         num_chars = self.max_digits
    709         # Allow for a decimal point
    710         if self.decimal_places > 0:
    711             num_chars += 1
    712         # Allow for a minus sign
    713         if value < 0:
    714             num_chars += 1
    715 
    716         return u"%.*f" % (self.decimal_places, value)
     728        # Method moved to django.db.backends.util.
     729        #
     730        # It is preserved because it is used by the oracle backend
     731        # (django.db.backends.oracle.query), and also for
     732        # backwards-compatibility with any external code which may have used
     733        # this method.
     734        from django.db.backends import util
     735        return util.format_number(value, self.max_digits, self.decimal_places)
    717736
    718737    def get_db_prep_save(self, value):
    719         value = self._format(value)
    720         return super(DecimalField, self).get_db_prep_save(value)
     738        return connection.ops.value_to_db_decimal(value, self.max_digits,
     739                                                  self.decimal_places)
    721740
    722741    def get_db_prep_lookup(self, lookup_type, value):
     742        value_to_db_decimal = connection.ops.value_to_db_decimal
    723743        if lookup_type == 'range':
    724             value = [self._format(v) for v in value]
     744            value = [value_to_db_decimal(v, self.max_digits,
     745                                         self.decimal_places)
     746                     for v in value]
    725747        else:
    726             value = self._format(value)
     748            value = value_to_db_decimal(value, self.max_digits,
     749                                        self.decimal_places)
    727750        return super(DecimalField, self).get_db_prep_lookup(lookup_type, value)
    728751
    729752    def get_manipulator_field_objs(self):
    class FloatField(Field):  
    898921class FloatField(Field):
    899922    empty_strings_allowed = False
    900923
     924    def get_db_prep_save(self, value):
     925        if value is None:
     926            return None
     927        return float(value)
     928
     929    def get_db_prep_lookup(self, lookup_type, value):
     930        if lookup_type == 'range':
     931            value = [float(v) for v in value]
     932        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     933            value = float(value)
     934        return Field.get_db_prep_lookup(self, lookup_type, value)
     935
    901936    def get_manipulator_field_objs(self):
    902937        return [oldforms.FloatField]
    903938
    class ImageField(FileField):  
    948983
    949984class IntegerField(Field):
    950985    empty_strings_allowed = False
     986    def get_db_prep_save(self, value):
     987        if value is None:
     988            return None
     989        return int(value)
     990
     991    def get_db_prep_lookup(self, lookup_type, value):
     992        if lookup_type == 'range':
     993            value = [int(v) for v in value]
     994        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     995            value = int(value)
     996        return Field.get_db_prep_lookup(self, lookup_type, value)
     997
    951998    def get_manipulator_field_objs(self):
    952999        return [oldforms.IntegerField]
    9531000
    class NullBooleanField(Field):  
    9951042        if value in ('f', 'False', '0'): return False
    9961043        raise validators.ValidationError, _("This value must be either None, True or False.")
    9971044
     1045    def get_db_prep_save(self, value):
     1046        if value is None:
     1047            return None
     1048        return bool(value)
     1049
     1050    def get_db_prep_lookup(self, lookup_type, value):
     1051        if lookup_type == 'exact' and value is not None:
     1052            value = bool(value)
     1053        return Field.get_db_prep_lookup(self, lookup_type, value)
     1054
     1055
    9981056    def get_manipulator_field_objs(self):
    9991057        return [oldforms.NullBooleanField]
    10001058
    class NullBooleanField(Field):  
    10031061        defaults.update(kwargs)
    10041062        return super(NullBooleanField, self).formfield(**defaults)
    10051063
    1006 class PhoneNumberField(IntegerField):
     1064class PhoneNumberField(Field):
    10071065    def get_manipulator_field_objs(self):
    10081066        return [oldforms.PhoneNumberField]
    10091067
    class TimeField(Field):  
    10851143    def get_internal_type(self):
    10861144        return "TimeField"
    10871145
     1146    def to_python(self, value):
     1147        if value is None:
     1148            return None
     1149        if isinstance(value, datetime.time):
     1150            return value
     1151
     1152        # Attempt to parse a datetime:
     1153        value = smart_str(value)
     1154        # split usecs, because they are not recognized by strptime.
     1155        if '.' in value:
     1156            try:
     1157                value, usecs = value.split('.')
     1158                usecs = int(usecs)
     1159            except ValueError:
     1160                raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.')
     1161        else:
     1162            usecs = 0
     1163        kwargs = {'microsecond': usecs}
     1164
     1165        try: # Seconds are optional, so try converting seconds first.
     1166            return datetime.time(*time.strptime(value, '%H:%M:%S')[3:6],
     1167                                 **kwargs)
     1168        except ValueError:
     1169            try: # Try without seconds.
     1170                return datetime.datetime(*time.strptime(value, '%H:%M')[:5],
     1171                                         **kwargs)
     1172            except ValueError:
     1173                raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.')
     1174
    10881175    def get_db_prep_lookup(self, lookup_type, value):
    1089         if connection.features.time_field_needs_date:
    1090             # Oracle requires a date in order to parse.
    1091             def prep(value):
    1092                 if isinstance(value, datetime.time):
    1093                     value = datetime.datetime.combine(datetime.date(1900, 1, 1), value)
    1094                 return smart_unicode(value)
    1095         else:
    1096             prep = smart_unicode
     1176        value_to_db_time = connection.ops.value_to_db_time
    10971177        if lookup_type == 'range':
    1098             value = [prep(v) for v in value]
    1099         else:
    1100             value = prep(value)
     1178            value = [value_to_db_time(self.to_python(v)) for v in value]
     1179        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     1180            value = value_to_db_time(self.to_python(value))
    11011181        return Field.get_db_prep_lookup(self, lookup_type, value)
    11021182
    11031183    def pre_save(self, model_instance, add):
    class TimeField(Field):  
    11091189            return super(TimeField, self).pre_save(model_instance, add)
    11101190
    11111191    def get_db_prep_save(self, value):
    1112         # Casts dates into string format for entry into database.
    1113         if value is not None:
    1114             # MySQL will throw a warning if microseconds are given, because it
    1115             # doesn't support microseconds.
    1116             if not connection.features.supports_usecs and hasattr(value, 'microsecond'):
    1117                 value = value.replace(microsecond=0)
    1118             if connection.features.time_field_needs_date:
    1119                 # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field.
    1120                 if isinstance(value, datetime.time):
    1121                     value = datetime.datetime(1900, 1, 1, value.hour, value.minute,
    1122                                               value.second, value.microsecond)
    1123                 elif isinstance(value, basestring):
    1124                     value = datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6]))
    1125             else:
    1126                 value = smart_unicode(value)
    1127         return Field.get_db_prep_save(self, value)
     1192        # Casts times into the format expected by the backend
     1193        return connection.ops.value_to_db_time(self.to_python(value))
    11281194
    11291195    def get_manipulator_field_objs(self):
    11301196        return [oldforms.TimeField]
  • tests/modeltests/custom_methods/models.py

    diff -r 7dfb4f5c1bb0 tests/modeltests/custom_methods/models.py
    a b class Article(models.Model):  
    3131            SELECT id, headline, pub_date
    3232            FROM custom_methods_article
    3333            WHERE pub_date = %s
    34                 AND id != %s""", [str(self.pub_date), self.id])
     34                AND id != %s""", [connection.ops.value_to_db_date(self.pub_date),
     35                                  self.id])
    3536        # The asterisk in "(*row)" tells Python to expand the list into
    3637        # positional arguments to Article().
    3738        return [self.__class__(*row) for row in cursor.fetchall()]
  • tests/regressiontests/model_fields/tests.py

    diff -r 7dfb4f5c1bb0 tests/regressiontests/model_fields/tests.py
    a b ValidationError: [u'This value must be a  
    2020>>> x = f.to_python(2)
    2121>>> y = f.to_python('2.6')
    2222
    23 >>> f.get_db_prep_save(x)
     23>>> f._format(x)
    2424u'2.0'
    25 >>> f.get_db_prep_save(y)
     25>>> f._format(y)
    2626u'2.6'
    27 >>> f.get_db_prep_save(None)
    28 >>> f.get_db_prep_lookup('exact', x)
    29 [u'2.0']
    30 >>> f.get_db_prep_lookup('exact', y)
    31 [u'2.6']
     27>>> f._format(None)
    3228>>> f.get_db_prep_lookup('exact', None)
    3329[None]
    3430
     31# DateTimeField and TimeField to_python should support usecs:
     32>>> f = DateTimeField()
     33>>> f.to_python('2001-01-02 03:04:05.000006')
     34datetime.datetime(2001, 1, 2, 3, 4, 5, 6)
     35>>> f.to_python('2001-01-02 03:04:05.999999')
     36datetime.datetime(2001, 1, 2, 3, 4, 5, 999999)
     37
     38>>> f = TimeField()
     39>>> f.to_python('01:02:03.000004')
     40datetime.time(1, 2, 3, 4)
     41>>> f.to_python('01:02:03.999999')
     42datetime.time(1, 2, 3, 999999)
     43
     44
    3545"""
  • tests/regressiontests/model_regress/models.py

    diff -r 7dfb4f5c1bb0 tests/regressiontests/model_regress/models.py
    a b class Movie(models.Model):  
    2828
    2929class Party(models.Model):
    3030    when = models.DateField()
     31
     32class Event(models.Model):
     33    when = models.DateTimeField()
    3134
    3235__test__ = {'API_TESTS': """
    3336(NOTE: Part of the regression test here is merely parsing the model
    5000  
    6871>>> [p.when for p in Party.objects.filter(when__year = 1998)]
    6972[datetime.date(1998, 12, 31)]
    7073
     74# Check that get_next_by_FIELD and get_previous_by_FIELD don't crash when we
     75# have usecs values stored on the database
     76#
     77# [It crashed after the Field.get_db_prep_* refactor, because on most backends
     78#  DateTimeFields supports usecs, but DateTimeField.to_python didn't recognize
     79#  them. (Note that Model._get_next_or_previous_by_FIELD coerces values to
     80#  strings)]
     81#
     82>>> e = Event.objects.create(when = datetime.datetime(2000, 1, 1, 16, 0, 0, 500))
     83>>> e = Event.objects.create(when = datetime.datetime(2000, 1, 1, 6, 0, 0, 400))
     84>>> e = Event.objects.create(when = datetime.datetime(2000, 1, 1, 13, 0, 0, 990))
     85>>> e = Event.objects.create(when = datetime.datetime(2000, 1, 1, 12, 0, 20, 24))
     86>>> e.get_next_by_when().when
     87datetime.datetime(2000, 1, 1, 13, 0, 0, 990)
     88>>> e.get_previous_by_when().when
     89datetime.datetime(2000, 1, 1, 6, 0, 0, 400)
    7190"""
    7291}
Back to Top