Django

Code

Changeset 8131

Show
Ignore:
Timestamp:
07/29/08 00:09:29 (4 months ago)
Author:
mtredinnick
Message:

Fixed #7560 -- Moved a lot of the value conversion preparation for
loading/saving interactions with the databases into django.db.backend. This
helps external db backend writers and removes a bunch of database-specific
if-tests in django.db.models.fields.

Great work from Leo Soto.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/db/backends/__init__.py

    r7926 r8131  
    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 
     9from django.utils import datetime_safe 
    710 
    811class BaseDatabaseWrapper(local): 
     
    3740 
    3841    def make_debug_cursor(self, cursor): 
    39         from django.db.backends import util 
    4042        return util.CursorDebugWrapper(cursor, self) 
    4143 
     
    4345    allows_group_by_ordinal = True 
    4446    inline_fk_references = True 
     47    # True if django.db.backend.utils.typecast_timestamp is used on values 
     48    # returned from dates() calls. 
    4549    needs_datetime_string_cast = True 
    4650    supports_constraints = True 
     
    5054    empty_fetchmany_value = [] 
    5155    update_can_self_select = True 
    52     supports_usecs = True 
    53     time_field_needs_date = False 
    5456    interprets_empty_strings_as_nulls = False 
    55     date_field_supports_time_value = True 
    5657    can_use_chunked_reads = True 
    5758 
     
    264265        from django.utils.encoding import smart_unicode 
    265266        return smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_") 
     267 
     268    def value_to_db_date(self, value): 
     269        """ 
     270        Transform a date value to an object compatible with what is expected 
     271        by the backend driver for date columns. 
     272        """ 
     273        if value is None: 
     274            return None 
     275        return datetime_safe.new_date(value).strftime('%Y-%m-%d') 
     276 
     277    def value_to_db_datetime(self, value): 
     278        """ 
     279        Transform a datetime value to an object compatible with what is expected 
     280        by the backend driver for date columns. 
     281        """ 
     282        if value is None: 
     283            return None 
     284        return unicode(value) 
     285 
     286    def value_to_db_time(self, value): 
     287        """ 
     288        Transform a datetime value to an object compatible with what is expected 
     289        by the backend driver for date columns. 
     290        """ 
     291        if value is None: 
     292            return None 
     293        return unicode(value) 
     294 
     295    def value_to_db_decimal(self, value, max_digits, decimal_places): 
     296        """ 
     297        Transform a decimal.Decimal value to an object compatible with what is 
     298        expected by the backend driver for decimal (numeric) columns. 
     299        """ 
     300        if value is None: 
     301            return None 
     302        return util.format_number(value, max_digits, decimal_places) 
     303 
     304    def year_lookup_bounds(self, value): 
     305        """ 
     306        Returns a two-elements list with the lower and upper bound to be used 
     307        with a BETWEEN operator to query a field value using a year lookup 
     308 
     309        `value` is an int, containing the looked-up year. 
     310        """ 
     311        first = '%s-01-01 00:00:00' 
     312        second = '%s-12-31 23:59:59.999999' 
     313        return [first % value, second % value] 
     314 
     315    def year_lookup_bounds_for_date_field(self, value): 
     316        """ 
     317        Returns a two-elements list with the lower and upper bound to be used 
     318        with a BETWEEN operator to query a DateField value using a year lookup 
     319 
     320        `value` is an int, containing the looked-up year. 
     321 
     322        By default, it just calls `self.year_lookup_bounds`. Some backends need 
     323        this hook because on their DB date fields can't be compared to values 
     324        which include a time part. 
     325        """ 
     326        return self.year_lookup_bounds(value) 
     327 
  • django/trunk/django/db/backends/mysql/base.py

    r7852 r8131  
    6464    empty_fetchmany_value = () 
    6565    update_can_self_select = False 
    66     supports_usecs = False 
    6766 
    6867class DatabaseOperations(BaseDatabaseOperations): 
     
    124123        else: 
    125124            return [] 
     125 
     126    def value_to_db_datetime(self, value): 
     127        # MySQL doesn't support microseconds 
     128        if value is None: 
     129            return None 
     130        return unicode(value.replace(microsecond=0)) 
     131 
     132    def value_to_db_time(self, value): 
     133        # MySQL doesn't support microseconds 
     134        if value is None: 
     135            return None 
     136        return unicode(value.replace(microsecond=0)) 
     137 
     138    def year_lookup_bounds(self, value): 
     139        # Again, no microseconds 
     140        first = '%s-01-01 00:00:00' 
     141        second = '%s-12-31 23:59:59.99' 
     142        return [first % value, second % value] 
    126143 
    127144class DatabaseWrapper(BaseDatabaseWrapper): 
  • django/trunk/django/db/backends/oracle/base.py

    r8046 r8131  
    66 
    77import os 
     8import datetime 
     9import time 
    810 
    911from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 
     
    2931    uses_case_insensitive_names = True 
    3032    uses_custom_query_class = True 
    31     time_field_needs_date = True 
    3233    interprets_empty_strings_as_nulls = True 
    33     date_field_supports_time_value = False 
    3434 
    3535class DatabaseOperations(BaseDatabaseOperations): 
     
    180180    def tablespace_sql(self, tablespace, inline=False): 
    181181        return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), self.quote_name(tablespace)) 
     182 
     183    def value_to_db_time(self, value): 
     184        if value is None: 
     185            return None 
     186        if isinstance(value, basestring): 
     187            return datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6])) 
     188        return datetime.datetime(1900, 1, 1, value.hour, value.minute, 
     189                                 value.second, value.microsecond) 
     190 
     191    def year_lookup_bounds_for_date_field(self, value): 
     192        first = '%s-01-01' 
     193        second = '%s-12-31' 
     194        return [first % value, second % value] 
     195 
     196 
    182197 
    183198class DatabaseWrapper(BaseDatabaseWrapper): 
  • django/trunk/django/db/backends/sqlite3/base.py

    r7956 r8131  
    8585        return sql 
    8686 
     87    def year_lookup_bounds(self, value): 
     88        first = '%s-01-01' 
     89        second = '%s-12-31 23:59:59.999999' 
     90        return [first % value, second % value] 
     91 
     92 
    8793class DatabaseWrapper(BaseDatabaseWrapper): 
    8894    features = DatabaseFeatures() 
     
    160166    except (ValueError, TypeError): 
    161167        return None 
    162     return str(getattr(dt, lookup_type)
     168    return getattr(dt, lookup_type
    163169 
    164170def _sqlite_date_trunc(lookup_type, dt): 
  • django/trunk/django/db/backends/util.py

    r7259 r8131  
    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/trunk/django/db/models/fields/__init__.py

    r8127 r8131  
    219219        return getattr(model_instance, self.attname) 
    220220 
     221    def get_db_prep_value(self, value): 
     222        """Returns field's value prepared for interacting with the database 
     223        backend. 
     224 
     225        Used by the default implementations of ``get_db_prep_save``and 
     226        `get_db_prep_lookup``` 
     227        """ 
     228        return value 
     229 
    221230    def get_db_prep_save(self, value): 
    222231        "Returns field's value prepared for saving into a database." 
    223         return value 
     232        return self.get_db_prep_value(value) 
    224233 
    225234    def get_db_prep_lookup(self, lookup_type, value): 
     
    228237            sql, params = value.as_sql() 
    229238            return QueryWrapper(('(%s)' % sql), params) 
    230         if lookup_type in ('exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'search'): 
     239        if lookup_type in ('regex', 'iregex', 'month', 'day', 'search'): 
    231240            return [value] 
     241        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'): 
     242            return [self.get_db_prep_value(value)] 
    232243        elif lookup_type in ('range', 'in'): 
    233             return value 
     244            return [self.get_db_prep_value(v) for v in value] 
    234245        elif lookup_type in ('contains', 'icontains'): 
    235246            return ["%%%s%%" % connection.ops.prep_for_like_query(value)] 
     
    247258            except ValueError: 
    248259                raise ValueError("The __year lookup type requires an integer argument") 
    249             if settings.DATABASE_ENGINE == 'sqlite3': 
    250                 first = '%s-01-01' 
    251                 second = '%s-12-31 23:59:59.999999' 
    252             elif not connection.features.date_field_supports_time_value and self.get_internal_type() == 'DateField': 
    253                 first = '%s-01-01' 
    254                 second = '%s-12-31' 
    255             elif not connection.features.supports_usecs: 
    256                 first = '%s-01-01 00:00:00' 
    257                 second = '%s-12-31 23:59:59.99' 
     260 
     261            if self.get_internal_type() == 'DateField': 
     262                return connection.ops.year_lookup_bounds_for_date_field(value) 
    258263            else: 
    259                 first = '%s-01-01 00:00:00' 
    260                 second = '%s-12-31 23:59:59.999999' 
    261             return [first % value, second % value] 
     264                return connection.ops.year_lookup_bounds(value) 
     265 
    262266        raise TypeError("Field has invalid lookup: %s" % lookup_type) 
    263267 
     
    458462            raise validators.ValidationError, _("This value must be an integer.") 
    459463 
     464    def get_db_prep_value(self, value): 
     465        if value is None: 
     466            return None 
     467        return int(value) 
     468 
    460469    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): 
    461470        if not rel: 
     
    498507        if value in ('f', 'False', '0'): return False 
    499508        raise validators.ValidationError, _("This value must be either True or False.") 
     509 
     510    def get_db_prep_value(self, value): 
     511        if value is None: 
     512            return None 
     513        return bool(value) 
    500514 
    501515    def get_manipulator_field_objs(self): 
     
    560574            raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 
    561575 
    562     def get_db_prep_lookup(self, lookup_type, value): 
    563         if lookup_type in ('range', 'in'): 
    564             value = [smart_unicode(v) for v in value] 
    565         elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte') and hasattr(value, 'strftime'): 
    566             value = datetime_safe.new_date(value).strftime('%Y-%m-%d') 
    567         else: 
    568             value = smart_unicode(value) 
    569         return Field.get_db_prep_lookup(self, lookup_type, value) 
    570  
    571576    def pre_save(self, model_instance, add): 
    572577        if self.auto_now or (self.auto_now_add and add): 
     
    592597            return self.editable or self.auto_now or self.auto_now_add 
    593598 
    594     def get_db_prep_save(self, value): 
    595         # Casts dates into string format for entry into database. 
    596         if value is not None: 
    597             try: 
    598                 value = datetime_safe.new_date(value).strftime('%Y-%m-%d') 
    599             except AttributeError: 
    600                 # If value is already a string it won't have a strftime method, 
    601                 # so we'll just let it pass through. 
    602                 pass 
    603         return Field.get_db_prep_save(self, value) 
     599    def get_db_prep_value(self, value): 
     600        # Casts dates into the format expected by the backend 
     601        return connection.ops.value_to_db_date(self.to_python(value)) 
    604602 
    605603    def get_manipulator_field_objs(self): 
     
    630628        if isinstance(value, datetime.date): 
    631629            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} 
    632643        try: # Seconds are optional, so try converting seconds first. 
    633             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 
    634647        except ValueError: 
    635648            try: # Try without seconds. 
    636                 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) 
    637651            except ValueError: # Try without hour/minutes/seconds. 
    638652                try: 
    639                     return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3]) 
     653                    return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3], 
     654                                             **kwargs) 
    640655                except ValueError: 
    641                     raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 
    642  
    643     def get_db_prep_save(self, value): 
    644         # Casts dates into string format for entry into database. 
    645         if value is not None: 
    646             # MySQL will throw a warning if microseconds are given, because it 
    647             # doesn't support microseconds. 
    648             if not connection.features.supports_usecs and hasattr(value, 'microsecond'): 
    649                 value = value.replace(microsecond=0) 
    650             value = smart_unicode(value) 
    651         return Field.get_db_prep_save(self, value) 
    652  
    653     def get_db_prep_lookup(self, lookup_type, value): 
    654         if lookup_type in ('range', 'in'): 
    655             value = [smart_unicode(v) for v in value] 
    656         else: 
    657             value = smart_unicode(value) 
    658         return Field.get_db_prep_lookup(self, lookup_type, value) 
     656                    raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[ss[.uuuuuu]] format.') 
     657 
     658    def get_db_prep_value(self, value): 
     659        # Casts dates into the format expected by the backend 
     660        return connection.ops.value_to_db_datetime(self.to_python(value)) 
    659661 
    660662    def get_manipulator_field_objs(self): 
     
    721723        decimal places. 
    722724        """ 
    723         num_chars = self.max_digits 
    724         # Allow for a decimal point 
    725         if self.decimal_places > 0: 
    726             num_chars += 1 
    727         # Allow for a minus sign 
    728         if value < 0: 
    729             num_chars += 1 
    730  
    731         return u"%.*f" % (self.decimal_places, value) 
    732  
    733     def get_db_prep_save(self, value): 
    734         value = self._format(value) 
    735         return super(DecimalField, self).get_db_prep_save(value) 
    736  
    737     def get_db_prep_lookup(self, lookup_type, value): 
    738         if lookup_type in ('range', 'in'): 
    739             value = [self._format(v) for v in value] 
    740         else: 
    741             value = self._format(value) 
    742         return super(DecimalField, self).get_db_prep_lookup(lookup_type, value) 
     725        # Method moved to django.db.backends.util. 
     726        # 
     727        # It is preserved because it is used by the oracle backend 
     728        # (django.db.backends.oracle.query), and also for 
     729        # backwards-compatibility with any external code which may have used 
     730        # this method. 
     731        from django.db.backends import util 
     732        return util.format_number(value, self.max_digits, self.decimal_places) 
     733 
     734    def get_db_prep_value(self, value): 
     735        return connection.ops.value_to_db_decimal(value, self.max_digits, 
     736                                                  self.decimal_places) 
    743737 
    744738    def get_manipulator_field_objs(self): 
     
    779773        return "FileField" 
    780774 
    781     def get_db_prep_save(self, value): 
     775    def get_db_prep_value(self, value): 
    782776        "Returns field's value prepared for saving into a database." 
    783777        # Need to convert UploadedFile objects provided via a form to unicode for database insertion 
     
    920914    empty_strings_allowed = False 
    921915 
     916    def get_db_prep_value(self, value): 
     917        if value is None: 
     918            return None 
     919        return float(value) 
     920 
    922921    def get_manipulator_field_objs(self): 
    923922        return [oldforms.FloatField] 
     
    967966class IntegerField(Field): 
    968967    empty_strings_allowed = False 
     968    def get_db_prep_value(self, value): 
     969        if value is None: 
     970            return None 
     971        return int(value) 
     972 
    969973    def get_manipulator_field_objs(self): 
    970974        return [oldforms.IntegerField] 
     
    10141018        raise validators.ValidationError, _("This value must be either None, True or False.") 
    10151019 
     1020    def get_db_prep_value(self, value): 
     1021        if value is None: 
     1022            return None 
     1023        return bool(value) 
     1024 
    10161025    def get_manipulator_field_objs(self): 
    10171026        return [oldforms.NullBooleanField] 
     
    10261035        return super(NullBooleanField, self).formfield(**defaults) 
    10271036 
    1028 class PhoneNumberField(IntegerField): 
     1037class PhoneNumberField(Field): 
    10291038    def get_manipulator_field_objs(self): 
    10301039        return [oldforms.PhoneNumberField] 
     
    11081117        return "TimeField" 
    11091118 
    1110     def get_db_prep_lookup(self, lookup_type, value): 
    1111         if connection.features.time_field_needs_date: 
    1112             # Oracle requires a date in order to parse. 
    1113             def prep(value): 
    1114                 if isinstance(value, datetime.time): 
    1115                     value = datetime.datetime.combine(datetime.date(1900, 1, 1), value) 
    1116                 return smart_unicode(value) 
    1117         else: 
    1118             prep = smart_unicode 
    1119         if lookup_type in ('range', 'in'): 
    1120             value = [prep(v) for v in value] 
    1121         else: 
    1122             value = prep(value) 
    1123         return Field.get_db_prep_lookup(self, lookup_type, value) 
     1119    def to_python(self, value): 
     1120        if value is None: 
     1121            return None 
     1122        if isinstance(value, datetime.time): 
     1123            return value 
     1124 
     1125        # Attempt to parse a datetime: 
     1126        value = smart_str(value) 
     1127        # split usecs, because they are not recognized by strptime. 
     1128        if '.' in value: 
     1129            try: 
     1130                value, usecs = value.split('.') 
     1131                usecs = int(usecs) 
     1132            except ValueError: 
     1133                raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.') 
     1134        else: 
     1135            usecs = 0 
     1136        kwargs = {'microsecond': usecs} 
     1137 
     1138        try: # Seconds are optional, so try converting seconds first. 
     1139            return datetime.time(*time.strptime(value, '%H:%M:%S')[3:6], 
     1140                                 **kwargs) 
     1141        except ValueError: 
     1142            try: # Try without seconds. 
     1143                return datetime.time(*time.strptime(value, '%H:%M')[3:5], 
     1144                                         **kwargs) 
     1145            except ValueError: 
     1146                raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.') 
    11241147 
    11251148    def pre_save(self, model_instance, add): 
     
    11311154            return super(TimeField, self).pre_save(model_instance, add) 
    11321155 
    1133     def get_db_prep_save(self, value): 
    1134         # Casts dates into string format for entry into database. 
    1135         if value is not None: 
    1136             # MySQL will throw a warning if microseconds are given, because it 
    1137             # doesn't support microseconds. 
    1138             if not connection.features.supports_usecs and hasattr(value, 'microsecond'): 
    1139                 value = value.replace(microsecond=0) 
    1140             if connection.features.time_field_needs_date: 
    1141                 # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field. 
    1142                 if isinstance(value, datetime.time): 
    1143                     value = datetime.datetime(1900, 1, 1, value.hour, value.minute, 
    1144                                               value.second, value.microsecond) 
    1145                 elif isinstance(value, basestring): 
    1146                     value = datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6])) 
    1147             else: 
    1148                 value = smart_unicode(value) 
    1149         return Field.get_db_prep_save(self, value) 
     1156    def get_db_prep_value(self, value): 
     1157        # Casts times into the format expected by the backend 
     1158        return connection.ops.value_to_db_time(self.to_python(value)) 
    11501159 
    11511160    def get_manipulator_field_objs(self): 
  • django/trunk/docs/custom_model_fields.txt

    r8125 r8131  
    386386mentioned earlier. Otherwise ``to_python()`` won't be called automatically. 
    387387 
    388 ``get_db_prep_save(self, value)`` 
    389 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     388``get_db_prep_value(self, value)`` 
     389~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    390390 
    391391This is the reverse of ``to_python()`` when working with the database backends 
     
    400400        # ... 
    401401 
    402         def get_db_prep_save(self, value): 
     402        def get_db_prep_value(self, value): 
    403403            return ''.join([''.join(l) for l in (value.north, 
    404404                    value.east, value.south, value.west)]) 
     405 
     406``get_db_prep_save(self, value)`` 
     407~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     408 
     409Same as the above, but called when the Field value must be *saved* to the 
     410database. As the default implementation just calls ``get_db_prep_value``, you 
     411shouldn't need to implement this method unless your custom field need a special 
     412conversion when being saved that is not the same as the used for normal query 
     413parameters (which is implemented by ``get_db_prep_value``). 
     414 
    405415 
    406416``pre_save(self, model_instance, add)`` 
     
    441451 
    442452If you needed to implement ``get_db_prep_save()``, you will usually need to 
    443 implement ``get_db_prep_lookup()``. The usual reason is because of the 
    444 ``range``  and ``in`` lookups. In these case, you will passed a list of 
    445 objects (presumably of the right type) and will need to convert them to a list 
    446 of things of the right type for passing to the database. Sometimes you can 
    447 reuse ``get_db_prep_save()``, or at least factor out some common pieces from 
    448 both methods into a help function. 
    449  
    450 For example:: 
     453implement ``get_db_prep_lookup()``. If you don't, ``get_db_prep_value`` will be 
     454called by the default implementation, to manage ``exact``, ``gt``, ``gte``, 
     455``lt``, ``lte``, ``in`` and ``range`` lookups. 
     456 
     457You may also want to implement this method to limit the lookup types that could 
     458be used with your custom field type. 
     459 
     460Note that, for ``range`` and ``in`` lookups, ``get_db_prep_lookup`` will receive 
     461a list of objects (presumably of the right type) and will need to convert them 
     462to a list of things of the right type for passing to the database. Most of the 
     463time, you can reuse ``get_db_prep_value()``, or at least factor out some common 
     464pieces. 
     465 
     466For example, the following code implements ``get_db_prep_lookup`` to limit the 
     467accepted lookup types to ``exact`` and ``in``:: 
    451468 
    452469    class HandField(models.Field): 
     
    456473            # We only handle 'exact' and 'in'. All others are errors. 
    457474            if lookup_type == 'exact': 
    458                 return self.get_db_prep_save(value) 
     475                return self.get_db_prep_value(value) 
    459476            elif lookup_type == 'in': 
    460                 return [self.get_db_prep_save(v) for v in value] 
     477                return [self.get_db_prep_value(v) for v in value] 
    461478            else: 
    462479                raise TypeError('Lookup type %r not supported.' % lookup_type) 
     
    558575        def flatten_data(self, follow, obj=None): 
    559576            value = self._get_val_from_obj(obj) 
    560             return {self.attname: self.get_db_prep_save(value)} 
     577            return {self.attname: self.get_db_prep_value(value)} 
    561578 
    562579Some general advice 
  • django/trunk/tests/modeltests/custom_methods/models.py

    r5876 r8131  
    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(). 
  • django/trunk/tests/modeltests/validation/models.py

    r7322 r8131  
    1717    favorite_moment = models.DateTimeField() 
    1818    email = models.EmailField() 
     19    best_time = models.TimeField() 
    1920 
    2021    def __unicode__(self): 
     
    2930...     'birthdate': datetime.date(2000, 5, 3), 
    3031...     'favorite_moment': datetime.datetime(2002, 4, 3, 13, 23), 
    31 ...     'email': 'john@example.com' 
     32...     'email': 'john@example.com', 
     33...     'best_time': datetime.time(16, 20), 
    3234... } 
    3335>>> p = Person(**valid_params) 
     
    131133datetime.datetime(2002, 4, 3, 0, 0) 
    132134 
     135>>> p = Person(**dict(valid_params, best_time='16:20:00')) 
     136>>> p.validate() 
     137{} 
     138>>> p.best_time 
     139datetime.time(16, 20) 
     140 
     141>>> p = Person(**dict(valid_params, best_time='16:20')) 
     142>>> p.validate() 
     143{} 
     144>>> p.best_time 
     145datetime.time(16, 20) 
     146 
     147>>> p = Person(**dict(valid_params, best_time='bar')) 
     148>>> p.validate()['best_time'] 
     149[u'Enter a valid time in HH:MM[:ss[.uuuuuu]] format.'] 
     150 
    133151>>> p = Person(**dict(valid_params, email='john@example.com')) 
    134152>>> p.validate() 
     
    154172>>> errors['birthdate'] 
    155173[u'This field is required.'] 
     174>>> errors['best_time'] 
     175[u'This field is required.'] 
    156176 
    157177"""} 
  • django/trunk/tests/regressiontests/model_fields/tests.py

    r7797 r8131  
    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""" 
  • django/trunk/tests/regressiontests/model_regress/models.py

    r7359 r8131  
    2929class Party(models.Model): 
    3030    when = models.DateField() 
     31 
     32class Event(models.Model): 
     33    when = models.DateTimeField() 
    3134 
    3235__test__ = {'API_TESTS': """ 
     
    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)) 
     83>>> e = Event.objects.create(when = datetime.datetime(2000, 1, 1, 6, 1, 1)) 
     84>>> e = Event.objects.create(when = datetime.datetime(2000, 1, 1, 13, 1, 1)) 
     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, 1, 1) 
     88>>> e.get_previous_by_when().when 
     89datetime.datetime(2000, 1, 1, 6, 1, 1) 
    7190""" 
    7291}