Ticket #7560: get_db_prep_refactor2.patch

File get_db_prep_refactor2.patch, 18.1 KB (added by Adam Vandenberg, 16 years ago)

Patch against revision 7818

  • django/db/backends/__init__.py

     
    55    # Import copy of _thread_local.py from Python 2.4
    66    from django.utils._threading_local import local
    77
     8from django.db.backends import util
     9
    810class BaseDatabaseWrapper(local):
    911    """
    1012    Represents a database connection.
     
    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
     
    272275        """Prepares a value for use in a LIKE query."""
    273276        from django.utils.encoding import smart_unicode
    274277        return smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
     278
     279    def value_to_db_date(self, value):
     280        """
     281        Transform a date value to an object compatible with what is expected
     282        by the backend driver for date columns.
     283        """
     284        if value is None:
     285            return None
     286        return value.strftime('%Y-%m-%d')
     287
     288    def value_to_db_datetime(self, value):
     289        """
     290        Transform a datetime value to an object compatible with what is expected
     291        by the backend driver for date columns.
     292        """
     293        if value is None:
     294            return None
     295        return unicode(value) # XXX: Why not just str(value)?
     296
     297    def value_to_db_time(self, value):
     298        """
     299        Transform a datetime value to an object compatible with what is expected
     300        by the backend driver for date columns.
     301        """
     302        if value is None:
     303            return None
     304        return unicode(value) # XXX: Why not just str(value)?
     305
     306    def value_to_db_decimal(self, value, max_digits, decimal_places):
     307        """
     308        Transform a decimal.Decimal value to an object compatible with what is
     309        expected by the backend driver for decimal (numeric) columns.
     310        """
     311        if value is None:
     312            return None
     313        return util.format_number(value, max_digits, decimal_places)
  • django/db/backends/mysql/base.py

     
    131131        else:
    132132            return []
    133133
     134    def value_to_db_datetime(self, value):
     135        # MySQL doesn't support microseconds
     136        if value is None:
     137            return None
     138        # XXX: Why not just str(value)?
     139        return unicode(value.replace(microsecond=0))
     140
     141    def value_to_db_time(self, value):
     142        # MySQL doesn't support microseconds
     143        if value is None:
     144            return None
     145        # XXX: Why not just str(value)?
     146        return unicode(value.replace(microsecond=0))
     147
    134148class DatabaseWrapper(BaseDatabaseWrapper):
    135149    features = DatabaseFeatures()
    136150    ops = DatabaseOperations()
  • django/db/backends/oracle/base.py

     
    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
     
    183185    def tablespace_sql(self, tablespace, inline=False):
    184186        return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), self.quote_name(tablespace))
    185187
     188    def value_to_db_time(self, value):
     189        if value is None:
     190            return None
     191        if isinstance(value, basestring):
     192            return datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6]))
     193        return datetime.datetime(1900, 1, 1, value.hour, value.minute,
     194                                 value.second, value.microsecond)
     195
    186196class DatabaseWrapper(BaseDatabaseWrapper):
    187197    features = DatabaseFeatures()
    188198    ops = DatabaseOperations()
  • django/db/backends/sqlite3/base.py

     
    150150    try:
    151151        dt = util.typecast_timestamp(dt)
    152152    except (ValueError, TypeError):
     153        print "error!"
    153154        return None
    154     return str(getattr(dt, lookup_type))
     155    return getattr(dt, lookup_type)
    155156
    156157def _sqlite_date_trunc(lookup_type, dt):
    157158    try:
  • django/db/backends/util.py

     
    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/fields/__init__.py

     
    252252                value = int(value)
    253253            except ValueError:
    254254                raise ValueError("The __year lookup type requires an integer argument")
     255            if settings.DATABASE_ENGINE.endswith('zxjdbc'):
     256                # zxJDBC drivers should support dates
     257                first = datetime.datetime(value, 1, 1)
     258                second = datetime.datetime(value, 12, 31,
     259                                           23, 59, 59, 999999)
     260                return (first, second)
    255261            if settings.DATABASE_ENGINE == 'sqlite3':
    256262                first = '%s-01-01'
    257263                second = '%s-12-31 23:59:59.999999'
     
    453459        except (TypeError, ValueError):
    454460            raise validators.ValidationError, _("This value must be an integer.")
    455461
     462    def get_db_prep_save(self, value):
     463        if value is None:
     464            return None
     465        return int(value)
     466
     467    def get_db_prep_lookup(self, lookup_type, value):
     468        if lookup_type == 'range':
     469            value = [int(v) for v in value]
     470        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     471            value = int(value)
     472        return Field.get_db_prep_lookup(self, lookup_type, value)
     473
    456474    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
    457475        if not rel:
    458476            return [] # Don't add a FormField unless it's in a related context.
     
    492510        if value in ('f', 'False', '0'): return False
    493511        raise validators.ValidationError, _("This value must be either True or False.")
    494512
     513    def get_db_prep_save(self, value):
     514        if value is None:
     515            return None
     516        return bool(value)
     517
     518    def get_db_prep_lookup(self, lookup_type, value):
     519        if lookup_type == 'exact' and value is not None:
     520            value = bool(value)
     521        return Field.get_db_prep_lookup(self, lookup_type, value)
     522
    495523    def get_manipulator_field_objs(self):
    496524        return [oldforms.CheckboxField]
    497525
     
    554582            raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.')
    555583
    556584    def get_db_prep_lookup(self, lookup_type, value):
     585        value_to_db_date = connection.ops.value_to_db_date
    557586        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)
     587            value = [value_to_db_date(self.to_python(v)) for v in value]
     588        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     589            # Lookups with a date argument
     590            value = value_to_db_date(self.to_python(value))
     591        # else:
     592        #    value = smart_unicode(value)
    563593        return Field.get_db_prep_lookup(self, lookup_type, value)
    564594
    565595    def pre_save(self, model_instance, add):
     
    586616            return self.editable or self.auto_now or self.auto_now_add
    587617
    588618    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)
     619        # Casts dates into the format expected by the backend
     620        return connection.ops.value_to_db_date(self.to_python(value))
    598621
    599622    def get_manipulator_field_objs(self):
    600623        return [oldforms.DateField]
     
    631654                    raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
    632655
    633656    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)
     657        # Casts dates into the format expected by the backend
     658        return connection.ops.value_to_db_datetime(self.to_python(value))
    642659
    643660    def get_db_prep_lookup(self, lookup_type, value):
     661        value_to_db_datetime = connection.ops.value_to_db_datetime
    644662        if lookup_type == 'range':
    645             value = [smart_unicode(v) for v in value]
    646         else:
    647             value = smart_unicode(value)
     663            value = [value_to_db_datetime(self.to_python(v)) for v in value]
     664        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     665            value = value_to_db_datetime(self.to_python(value))
    648666        return Field.get_db_prep_lookup(self, lookup_type, value)
    649667
    650668    def get_manipulator_field_objs(self):
     
    705723        Formats a number into a string with the requisite number of digits and
    706724        decimal places.
    707725        """
    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
     726        # Method moved to django.db.backends.util.
     727        #
     728        # It is preserved because it is used by the oracle backend
     729        # (django.db.backends.oracle.query), and also for
     730        # backwards-compatibility with any external code which may have used
     731        # this method.
     732        from django.db.backends import util
     733        return util.format_number(value, self.max_digits, self.decimal_places)
    715734
    716         return u"%.*f" % (self.decimal_places, value)
    717 
    718735    def get_db_prep_save(self, value):
    719         value = self._format(value)
    720         return super(DecimalField, self).get_db_prep_save(value)
     736        return connection.ops.value_to_db_decimal(value, self.max_digits,
     737                                                  self.decimal_places)
    721738
    722739    def get_db_prep_lookup(self, lookup_type, value):
     740        value_to_db_decimal = connection.ops.value_to_db_decimal
    723741        if lookup_type == 'range':
    724             value = [self._format(v) for v in value]
     742            value = [value_to_db_decimal(v, self.max_digits,
     743                                         self.decimal_places)
     744                     for v in value]
    725745        else:
    726             value = self._format(value)
     746            value = value_to_db_decimal(value, self.max_digits,
     747                                        self.decimal_places)
    727748        return super(DecimalField, self).get_db_prep_lookup(lookup_type, value)
    728749
    729750    def get_manipulator_field_objs(self):
     
    898919class FloatField(Field):
    899920    empty_strings_allowed = False
    900921
     922    def get_db_prep_save(self, value):
     923        if value is None:
     924            return None
     925        return float(value)
     926
     927    def get_db_prep_lookup(self, lookup_type, value):
     928        if lookup_type == 'range':
     929            value = [float(v) for v in value]
     930        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     931            value = float(value)
     932        return Field.get_db_prep_lookup(self, lookup_type, value)
     933
    901934    def get_manipulator_field_objs(self):
    902935        return [oldforms.FloatField]
    903936
     
    948981
    949982class IntegerField(Field):
    950983    empty_strings_allowed = False
     984    def get_db_prep_save(self, value):
     985        if value is None:
     986            return None
     987        return int(value)
     988
     989    def get_db_prep_lookup(self, lookup_type, value):
     990        if lookup_type == 'range':
     991            value = [int(v) for v in value]
     992        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     993            value = int(value)
     994        return Field.get_db_prep_lookup(self, lookup_type, value)
     995
    951996    def get_manipulator_field_objs(self):
    952997        return [oldforms.IntegerField]
    953998
     
    9951040        if value in ('f', 'False', '0'): return False
    9961041        raise validators.ValidationError, _("This value must be either None, True or False.")
    9971042
     1043    def get_db_prep_save(self, value):
     1044        if value is None:
     1045            return None
     1046        return bool(value)
     1047
     1048    def get_db_prep_lookup(self, lookup_type, value):
     1049        if lookup_type == 'exact' and value is not None:
     1050            value = bool(value)
     1051        return Field.get_db_prep_lookup(self, lookup_type, value)
     1052
     1053
    9981054    def get_manipulator_field_objs(self):
    9991055        return [oldforms.NullBooleanField]
    10001056
     
    10031059        defaults.update(kwargs)
    10041060        return super(NullBooleanField, self).formfield(**defaults)
    10051061
    1006 class PhoneNumberField(IntegerField):
     1062class PhoneNumberField(Field):
    10071063    def get_manipulator_field_objs(self):
    10081064        return [oldforms.PhoneNumberField]
    10091065
     
    10851141    def get_internal_type(self):
    10861142        return "TimeField"
    10871143
     1144    def to_python(self, value):
     1145        if value is None:
     1146            return None
     1147        if isinstance(value, datetime.time):
     1148            return value
     1149        try: # Seconds are optional, so try converting seconds first.
     1150            return datetime.time(*time.strptime(value, '%H:%M:%S')[3:6])
     1151        except ValueError:
     1152            try: # Try without seconds.
     1153                return datetime.datetime(*time.strptime(value, '%H:%M')[:5])
     1154            except ValueError:
     1155                raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss] format.')
     1156
    10881157    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
     1158        value_to_db_time = connection.ops.value_to_db_time
    10971159        if lookup_type == 'range':
    1098             value = [prep(v) for v in value]
    1099         else:
    1100             value = prep(value)
     1160            value = [value_to_db_time(self.to_python(v)) for v in value]
     1161        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
     1162            value = value_to_db_time(self.to_python(value))
    11011163        return Field.get_db_prep_lookup(self, lookup_type, value)
    11021164
    11031165    def pre_save(self, model_instance, add):
     
    11091171            return super(TimeField, self).pre_save(model_instance, add)
    11101172
    11111173    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)
     1174        # Casts times into the format expected by the backend
     1175        return connection.ops.value_to_db_time(self.to_python(value))
    11281176
    11291177    def get_manipulator_field_objs(self):
    11301178        return [oldforms.TimeField]
  • tests/modeltests/custom_methods/models.py

     
    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()]
Back to Top