Ticket #7560: get_db_prep_refactor2.patch
File get_db_prep_refactor2.patch, 18.1 KB (added by , 16 years ago) |
---|
-
django/db/backends/__init__.py
5 5 # Import copy of _thread_local.py from Python 2.4 6 6 from django.utils._threading_local import local 7 7 8 from django.db.backends import util 9 8 10 class BaseDatabaseWrapper(local): 9 11 """ 10 12 Represents a database connection. … … 36 38 return cursor 37 39 38 40 def make_debug_cursor(self, cursor): 39 from django.db.backends import util40 41 return util.CursorDebugWrapper(cursor, self) 41 42 42 43 class BaseDatabaseFeatures(object): 43 44 allows_group_by_ordinal = True 44 45 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() 46 49 supports_constraints = True 47 50 supports_tablespaces = False 48 51 uses_case_insensitive_names = False … … 272 275 """Prepares a value for use in a LIKE query.""" 273 276 from django.utils.encoding import smart_unicode 274 277 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
131 131 else: 132 132 return [] 133 133 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 134 148 class DatabaseWrapper(BaseDatabaseWrapper): 135 149 features = DatabaseFeatures() 136 150 ops = DatabaseOperations() -
django/db/backends/oracle/base.py
5 5 """ 6 6 7 7 import os 8 import datetime 9 import time 8 10 9 11 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 10 12 from django.db.backends.oracle import query … … 183 185 def tablespace_sql(self, tablespace, inline=False): 184 186 return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), self.quote_name(tablespace)) 185 187 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 186 196 class DatabaseWrapper(BaseDatabaseWrapper): 187 197 features = DatabaseFeatures() 188 198 ops = DatabaseOperations() -
django/db/backends/sqlite3/base.py
150 150 try: 151 151 dt = util.typecast_timestamp(dt) 152 152 except (ValueError, TypeError): 153 print "error!" 153 154 return None 154 return str(getattr(dt, lookup_type))155 return getattr(dt, lookup_type) 155 156 156 157 def _sqlite_date_trunc(lookup_type, dt): 157 158 try: -
django/db/backends/util.py
117 117 hash = md5.md5(name).hexdigest()[:4] 118 118 119 119 return '%s%s' % (name[:length-4], hash) 120 121 def 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
252 252 value = int(value) 253 253 except ValueError: 254 254 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) 255 261 if settings.DATABASE_ENGINE == 'sqlite3': 256 262 first = '%s-01-01' 257 263 second = '%s-12-31 23:59:59.999999' … … 453 459 except (TypeError, ValueError): 454 460 raise validators.ValidationError, _("This value must be an integer.") 455 461 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 456 474 def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): 457 475 if not rel: 458 476 return [] # Don't add a FormField unless it's in a related context. … … 492 510 if value in ('f', 'False', '0'): return False 493 511 raise validators.ValidationError, _("This value must be either True or False.") 494 512 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 495 523 def get_manipulator_field_objs(self): 496 524 return [oldforms.CheckboxField] 497 525 … … 554 582 raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 555 583 556 584 def get_db_prep_lookup(self, lookup_type, value): 585 value_to_db_date = connection.ops.value_to_db_date 557 586 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) 563 593 return Field.get_db_prep_lookup(self, lookup_type, value) 564 594 565 595 def pre_save(self, model_instance, add): … … 586 616 return self.editable or self.auto_now or self.auto_now_add 587 617 588 618 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)) 598 621 599 622 def get_manipulator_field_objs(self): 600 623 return [oldforms.DateField] … … 631 654 raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 632 655 633 656 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)) 642 659 643 660 def get_db_prep_lookup(self, lookup_type, value): 661 value_to_db_datetime = connection.ops.value_to_db_datetime 644 662 if lookup_type == 'range': 645 value = [ smart_unicode(v) for v in value]646 el se: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)) 648 666 return Field.get_db_prep_lookup(self, lookup_type, value) 649 667 650 668 def get_manipulator_field_objs(self): … … 705 723 Formats a number into a string with the requisite number of digits and 706 724 decimal places. 707 725 """ 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) 715 734 716 return u"%.*f" % (self.decimal_places, value)717 718 735 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) 721 738 722 739 def get_db_prep_lookup(self, lookup_type, value): 740 value_to_db_decimal = connection.ops.value_to_db_decimal 723 741 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] 725 745 else: 726 value = self._format(value) 746 value = value_to_db_decimal(value, self.max_digits, 747 self.decimal_places) 727 748 return super(DecimalField, self).get_db_prep_lookup(lookup_type, value) 728 749 729 750 def get_manipulator_field_objs(self): … … 898 919 class FloatField(Field): 899 920 empty_strings_allowed = False 900 921 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 901 934 def get_manipulator_field_objs(self): 902 935 return [oldforms.FloatField] 903 936 … … 948 981 949 982 class IntegerField(Field): 950 983 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 951 996 def get_manipulator_field_objs(self): 952 997 return [oldforms.IntegerField] 953 998 … … 995 1040 if value in ('f', 'False', '0'): return False 996 1041 raise validators.ValidationError, _("This value must be either None, True or False.") 997 1042 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 998 1054 def get_manipulator_field_objs(self): 999 1055 return [oldforms.NullBooleanField] 1000 1056 … … 1003 1059 defaults.update(kwargs) 1004 1060 return super(NullBooleanField, self).formfield(**defaults) 1005 1061 1006 class PhoneNumberField( IntegerField):1062 class PhoneNumberField(Field): 1007 1063 def get_manipulator_field_objs(self): 1008 1064 return [oldforms.PhoneNumberField] 1009 1065 … … 1085 1141 def get_internal_type(self): 1086 1142 return "TimeField" 1087 1143 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 1088 1157 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 1097 1159 if lookup_type == 'range': 1098 value = [ prep(v) for v in value]1099 el se: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)) 1101 1163 return Field.get_db_prep_lookup(self, lookup_type, value) 1102 1164 1103 1165 def pre_save(self, model_instance, add): … … 1109 1171 return super(TimeField, self).pre_save(model_instance, add) 1110 1172 1111 1173 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)) 1128 1176 1129 1177 def get_manipulator_field_objs(self): 1130 1178 return [oldforms.TimeField] -
tests/modeltests/custom_methods/models.py
31 31 SELECT id, headline, pub_date 32 32 FROM custom_methods_article 33 33 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]) 35 36 # The asterisk in "(*row)" tells Python to expand the list into 36 37 # positional arguments to Article(). 37 38 return [self.__class__(*row) for row in cursor.fetchall()]