Ticket #7560: get_db_prep_refactor.patch
File get_db_prep_refactor.patch, 18.7 KB (added by , 16 years ago) |
---|
-
django/db/backends/__init__.py
diff -r ae5842633149 django/db/backends/__init__.py
a b except ImportError: 4 4 except ImportError: 5 5 # Import copy of _thread_local.py from Python 2.4 6 6 from django.utils._threading_local import local 7 8 from django.db.backends import util 7 9 8 10 class BaseDatabaseWrapper(local): 9 11 """ … … class BaseDatabaseWrapper(local): 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): … … class BaseDatabaseFeatures(object): 44 45 allows_unique_and_pk = True 45 46 autoindexes_primary_keys = True 46 47 inline_fk_references = True 47 needs_datetime_string_cast = True 48 needs_datetime_string_cast = True # uses 49 # django.db.backend.utils.typecast_timetamp 50 # on returned values from dates() 48 51 supports_constraints = True 49 52 supports_tablespaces = False 50 53 uses_case_insensitive_names = False … … class BaseDatabaseOperations(object): 274 277 """Prepares a value for use in a LIKE query.""" 275 278 from django.utils.encoding import smart_unicode 276 279 return smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_") 280 281 def value_to_db_date(self, value): 282 """ 283 Transform a date value to an object compatible with what is expected 284 by the backend driver for date columns. 285 """ 286 if value is None: 287 return None 288 return value.strftime('%Y-%m-%d') 289 290 def value_to_db_datetime(self, value): 291 """ 292 Transform a datetime value to an object compatible with what is expected 293 by the backend driver for date columns. 294 """ 295 if value is None: 296 return None 297 return unicode(value) # XXX: Why not just str(value)? 298 299 def value_to_db_time(self, value): 300 """ 301 Transform a datetime value to an object compatible with what is expected 302 by the backend driver for date columns. 303 """ 304 if value is None: 305 return None 306 return unicode(value) # XXX: Why not just str(value)? 307 308 def value_to_db_decimal(self, value, max_digits, decimal_places): 309 """ 310 Transform a decimal.Decimal value to an object compatible with what is 311 expected by the backend driver for decimal (numeric) columns. 312 """ 313 if value is None: 314 return None 315 return util.format_number(value, max_digits, decimal_places) -
django/db/backends/mysql/base.py
diff -r ae5842633149 django/db/backends/mysql/base.py
a b class DatabaseOperations(BaseDatabaseOpe 132 132 else: 133 133 return [] 134 134 135 def value_to_db_datetime(self, value): 136 # MySQL doesn't support microseconds 137 if value is None: 138 return None 139 # XXX: Why not just str(value)? 140 return unicode(value.replace(microsecond=0)) 141 142 def value_to_db_time(self, value): 143 # MySQL doesn't support microseconds 144 if value is None: 145 return None 146 # XXX: Why not just str(value)? 147 return unicode(value.replace(microsecond=0)) 148 135 149 class DatabaseWrapper(BaseDatabaseWrapper): 136 150 features = DatabaseFeatures() 137 151 ops = DatabaseOperations() -
django/db/backends/oracle/base.py
diff -r ae5842633149 django/db/backends/oracle/base.py
a b Requires cx_Oracle: http://www.python.ne 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 … … class DatabaseOperations(BaseDatabaseOpe 183 185 184 186 def tablespace_sql(self, tablespace, inline=False): 185 187 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) 186 196 187 197 class DatabaseWrapper(BaseDatabaseWrapper): 188 198 features = DatabaseFeatures() -
django/db/backends/sqlite3/base.py
diff -r ae5842633149 django/db/backends/sqlite3/base.py
a b def _sqlite_extract(lookup_type, dt): 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
diff -r ae5842633149 django/db/backends/util.py
a b def truncate_name(name, length=None): 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
diff -r ae5842633149 django/db/models/fields/__init__.py
a b class Field(object): 248 248 value = int(value) 249 249 except ValueError: 250 250 raise ValueError("The __year lookup type requires an integer argument") 251 if settings.DATABASE_ENGINE.endswith('zxjdbc'): 252 # zxJDBC drivers should support dates 253 first = datetime.datetime(value, 1, 1) 254 second = datetime.datetime(value, 12, 31, 255 23, 59, 59, 999999) 256 return (first, second) 251 257 if settings.DATABASE_ENGINE == 'sqlite3': 252 258 first = '%s-01-01' 253 259 second = '%s-12-31 23:59:59.999999' … … class AutoField(Field): 449 455 except (TypeError, ValueError): 450 456 raise validators.ValidationError, _("This value must be an integer.") 451 457 458 def get_db_prep_save(self, value): 459 if value is None: 460 return None 461 return int(value) 462 463 def get_db_prep_lookup(self, lookup_type, value): 464 if lookup_type == 'range': 465 value = [int(v) for v in value] 466 elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'): 467 value = int(value) 468 return Field.get_db_prep_lookup(self, lookup_type, value) 469 452 470 def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): 453 471 if not rel: 454 472 return [] # Don't add a FormField unless it's in a related context. … … class BooleanField(Field): 487 505 if value in ('t', 'True', '1'): return True 488 506 if value in ('f', 'False', '0'): return False 489 507 raise validators.ValidationError, _("This value must be either True or False.") 508 509 def get_db_prep_save(self, value): 510 if value is None: 511 return None 512 return bool(value) 513 514 def get_db_prep_lookup(self, lookup_type, value): 515 if lookup_type == 'exact' and value is not None: 516 value = bool(value) 517 return Field.get_db_prep_lookup(self, lookup_type, value) 490 518 491 519 def get_manipulator_field_objs(self): 492 520 return [oldforms.CheckboxField] … … class DateField(Field): 550 578 raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 551 579 552 580 def get_db_prep_lookup(self, lookup_type, value): 581 value_to_db_date = connection.ops.value_to_db_date 553 582 if lookup_type == 'range': 554 value = [smart_unicode(v) for v in value] 555 elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte') and hasattr(value, 'strftime'): 556 value = value.strftime('%Y-%m-%d') 557 else: 558 value = smart_unicode(value) 583 value = [value_to_db_date(self.to_python(v)) for v in value] 584 elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'): 585 # Lookups with a date argument 586 value = value_to_db_date(self.to_python(value)) 587 # else: 588 # value = smart_unicode(value) 559 589 return Field.get_db_prep_lookup(self, lookup_type, value) 560 590 561 591 def pre_save(self, model_instance, add): … … class DateField(Field): 582 612 return self.editable or self.auto_now or self.auto_now_add 583 613 584 614 def get_db_prep_save(self, value): 585 # Casts dates into string format for entry into database. 586 if value is not None: 587 try: 588 value = value.strftime('%Y-%m-%d') 589 except AttributeError: 590 # If value is already a string it won't have a strftime method, 591 # so we'll just let it pass through. 592 pass 593 return Field.get_db_prep_save(self, value) 615 # Casts dates into the format expected by the backend 616 return connection.ops.value_to_db_date(self.to_python(value)) 594 617 595 618 def get_manipulator_field_objs(self): 596 619 return [oldforms.DateField] … … class DateTimeField(DateField): 627 650 raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 628 651 629 652 def get_db_prep_save(self, value): 630 # Casts dates into string format for entry into database. 631 if value is not None: 632 # MySQL will throw a warning if microseconds are given, because it 633 # doesn't support microseconds. 634 if not connection.features.supports_usecs and hasattr(value, 'microsecond'): 635 value = value.replace(microsecond=0) 636 value = smart_unicode(value) 637 return Field.get_db_prep_save(self, value) 653 # Casts dates into the format expected by the backend 654 return connection.ops.value_to_db_datetime(self.to_python(value)) 638 655 639 656 def get_db_prep_lookup(self, lookup_type, value): 657 value_to_db_datetime = connection.ops.value_to_db_datetime 640 658 if lookup_type == 'range': 641 value = [ smart_unicode(v) for v in value]642 el se:643 value = smart_unicode(value)659 value = [value_to_db_datetime(self.to_python(v)) for v in value] 660 elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'): 661 value = value_to_db_datetime(self.to_python(value)) 644 662 return Field.get_db_prep_lookup(self, lookup_type, value) 645 663 646 664 def get_manipulator_field_objs(self): … … class DecimalField(Field): 701 719 Formats a number into a string with the requisite number of digits and 702 720 decimal places. 703 721 """ 704 num_chars = self.max_digits 705 # Allow for a decimal point 706 if self.decimal_places > 0: 707 num_chars += 1 708 # Allow for a minus sign 709 if value < 0: 710 num_chars += 1 711 712 return u"%.*f" % (self.decimal_places, value) 722 # Method moved to django.db.backends.util. 723 # 724 # It is preserved because it is used by the oracle backend 725 # (django.db.backends.oracle.query), and also for 726 # backwards-compatibility with any external code which may have used 727 # this method. 728 from django.db.backends import util 729 return util.format_number(value, self.max_digits, self.decimal_places) 713 730 714 731 def get_db_prep_save(self, value): 715 if value is not None: 716 value = self._format(value) 717 return super(DecimalField, self).get_db_prep_save(value) 732 return connection.ops.value_to_db_decimal(value, self.max_digits, 733 self.decimal_places) 718 734 719 735 def get_db_prep_lookup(self, lookup_type, value): 736 value_to_db_decimal = connection.ops.value_to_db_decimal 720 737 if lookup_type == 'range': 721 value = [self._format(v) for v in value] 738 value = [value_to_db_decimal(v, self.max_digits, 739 self.decimal_places) 740 for v in value] 722 741 else: 723 value = self._format(value) 742 value = value_to_db_decimal(value, self.max_digits, 743 self.decimal_places) 724 744 return super(DecimalField, self).get_db_prep_lookup(lookup_type, value) 725 745 726 746 def get_manipulator_field_objs(self): … … class FloatField(Field): 885 905 class FloatField(Field): 886 906 empty_strings_allowed = False 887 907 908 def get_db_prep_save(self, value): 909 if value is None: 910 return None 911 return float(value) 912 913 def get_db_prep_lookup(self, lookup_type, value): 914 if lookup_type == 'range': 915 value = [float(v) for v in value] 916 elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'): 917 value = float(value) 918 return Field.get_db_prep_lookup(self, lookup_type, value) 919 888 920 def get_manipulator_field_objs(self): 889 921 return [oldforms.FloatField] 890 922 … … class ImageField(FileField): 935 967 936 968 class IntegerField(Field): 937 969 empty_strings_allowed = False 970 def get_db_prep_save(self, value): 971 if value is None: 972 return None 973 return int(value) 974 975 def get_db_prep_lookup(self, lookup_type, value): 976 if lookup_type == 'range': 977 value = [int(v) for v in value] 978 elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'): 979 value = int(value) 980 return Field.get_db_prep_lookup(self, lookup_type, value) 981 938 982 def get_manipulator_field_objs(self): 939 983 return [oldforms.IntegerField] 940 984 … … class NullBooleanField(Field): 982 1026 if value in ('f', 'False', '0'): return False 983 1027 raise validators.ValidationError, _("This value must be either None, True or False.") 984 1028 1029 def get_db_prep_save(self, value): 1030 if value is None: 1031 return None 1032 return bool(value) 1033 1034 def get_db_prep_lookup(self, lookup_type, value): 1035 if lookup_type == 'exact' and value is not None: 1036 value = bool(value) 1037 return Field.get_db_prep_lookup(self, lookup_type, value) 1038 1039 985 1040 def get_manipulator_field_objs(self): 986 1041 return [oldforms.NullBooleanField] 987 1042 … … class NullBooleanField(Field): 990 1045 defaults.update(kwargs) 991 1046 return super(NullBooleanField, self).formfield(**defaults) 992 1047 993 class PhoneNumberField( IntegerField):1048 class PhoneNumberField(Field): 994 1049 def get_manipulator_field_objs(self): 995 1050 return [oldforms.PhoneNumberField] 996 1051 … … class TimeField(Field): 1072 1127 def get_internal_type(self): 1073 1128 return "TimeField" 1074 1129 1130 def to_python(self, value): 1131 if value is None: 1132 return None 1133 if isinstance(value, datetime.time): 1134 return value 1135 try: # Seconds are optional, so try converting seconds first. 1136 return datetime.time(*time.strptime(value, '%H:%M:%S')[3:6]) 1137 except ValueError: 1138 try: # Try without seconds. 1139 return datetime.datetime(*time.strptime(value, '%H:%M')[:5]) 1140 except ValueError: 1141 raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss] format.') 1142 1075 1143 def get_db_prep_lookup(self, lookup_type, value): 1076 if connection.features.time_field_needs_date: 1077 # Oracle requires a date in order to parse. 1078 def prep(value): 1079 if isinstance(value, datetime.time): 1080 value = datetime.datetime.combine(datetime.date(1900, 1, 1), value) 1081 return smart_unicode(value) 1082 else: 1083 prep = smart_unicode 1144 value_to_db_time = connection.ops.value_to_db_time 1084 1145 if lookup_type == 'range': 1085 value = [ prep(v) for v in value]1086 el se:1087 value = prep(value)1146 value = [value_to_db_time(self.to_python(v)) for v in value] 1147 elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'): 1148 value = value_to_db_time(self.to_python(value)) 1088 1149 return Field.get_db_prep_lookup(self, lookup_type, value) 1089 1150 1090 1151 def pre_save(self, model_instance, add): … … class TimeField(Field): 1096 1157 return super(TimeField, self).pre_save(model_instance, add) 1097 1158 1098 1159 def get_db_prep_save(self, value): 1099 # Casts dates into string format for entry into database. 1100 if value is not None: 1101 # MySQL will throw a warning if microseconds are given, because it 1102 # doesn't support microseconds. 1103 if not connection.features.supports_usecs and hasattr(value, 'microsecond'): 1104 value = value.replace(microsecond=0) 1105 if connection.features.time_field_needs_date: 1106 # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field. 1107 if isinstance(value, datetime.time): 1108 value = datetime.datetime(1900, 1, 1, value.hour, value.minute, 1109 value.second, value.microsecond) 1110 elif isinstance(value, basestring): 1111 value = datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6])) 1112 else: 1113 value = smart_unicode(value) 1114 return Field.get_db_prep_save(self, value) 1160 # Casts times into the format expected by the backend 1161 return connection.ops.value_to_db_time(self.to_python(value)) 1115 1162 1116 1163 def get_manipulator_field_objs(self): 1117 1164 return [oldforms.TimeField] -
tests/modeltests/custom_methods/models.py
diff -r ae5842633149 tests/modeltests/custom_methods/models.py
a b class Article(models.Model): 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()]