Changeset 8215 for django/branches/gis/django/db
- Timestamp:
- 08/05/08 12:15:33 (4 months ago)
- Files:
-
- django/branches/gis (modified) (1 prop)
- django/branches/gis/django/db/backends/__init__.py (modified) (5 diffs)
- django/branches/gis/django/db/backends/mysql/base.py (modified) (2 diffs)
- django/branches/gis/django/db/backends/oracle/base.py (modified) (6 diffs)
- django/branches/gis/django/db/backends/oracle/query.py (modified) (4 diffs)
- django/branches/gis/django/db/backends/sqlite3/base.py (modified) (2 diffs)
- django/branches/gis/django/db/backends/util.py (modified) (2 diffs)
- django/branches/gis/django/db/models/base.py (modified) (7 diffs)
- django/branches/gis/django/db/models/fields/__init__.py (modified) (25 diffs)
- django/branches/gis/django/db/models/fields/related.py (modified) (25 diffs)
- django/branches/gis/django/db/models/fields/subclassing.py (modified) (2 diffs)
- django/branches/gis/django/db/models/__init__.py (modified) (1 diff)
- django/branches/gis/django/db/models/query.py (modified) (4 diffs)
- django/branches/gis/django/db/models/sql/query.py (modified) (6 diffs)
- django/branches/gis/django/db/models/sql/where.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/gis
- Property svnmerge-integrated changed from /django/trunk:1-7978 to /django/trunk:1-8214
django/branches/gis/django/db/backends/__init__.py
r7979 r8215 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 9 from django.utils import datetime_safe 7 10 8 11 class BaseDatabaseWrapper(local): … … 37 40 38 41 def make_debug_cursor(self, cursor): 39 from django.db.backends import util40 42 return util.CursorDebugWrapper(cursor, self) 41 43 … … 43 45 allows_group_by_ordinal = True 44 46 inline_fk_references = True 47 # True if django.db.backend.utils.typecast_timestamp is used on values 48 # returned from dates() calls. 45 49 needs_datetime_string_cast = True 46 50 supports_constraints = True … … 50 54 empty_fetchmany_value = [] 51 55 update_can_self_select = True 52 supports_usecs = True53 time_field_needs_date = False54 56 interprets_empty_strings_as_nulls = False 55 date_field_supports_time_value = True56 57 can_use_chunked_reads = True 57 58 … … 264 265 from django.utils.encoding import smart_unicode 265 266 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 datetime 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 time 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/branches/gis/django/db/backends/mysql/base.py
r7918 r8215 64 64 empty_fetchmany_value = () 65 65 update_can_self_select = False 66 supports_usecs = False67 66 68 67 class DatabaseOperations(BaseDatabaseOperations): … … 124 123 else: 125 124 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] 126 143 127 144 class DatabaseWrapper(BaseDatabaseWrapper): django/branches/gis/django/db/backends/oracle/base.py
r7918 r8215 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 11 from django.utils.datastructures import SortedDict12 13 from django.utils.encoding import smart_str, force_unicode 13 14 … … 30 31 uses_case_insensitive_names = True 31 32 uses_custom_query_class = True 32 time_field_needs_date = True33 33 interprets_empty_strings_as_nulls = True 34 date_field_supports_time_value = False35 34 36 35 class DatabaseOperations(BaseDatabaseOperations): … … 181 180 def tablespace_sql(self, tablespace, inline=False): 182 181 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 183 197 184 198 class DatabaseWrapper(BaseDatabaseWrapper): … … 246 260 class OracleParam(object): 247 261 """ 248 Wrapper object for formatting parameters for Oracle. If the string 249 representation of the value is large enough (greater than 4000 characters) 262 Wrapper object for formatting parameters for Oracle. If the string 263 representation of the value is large enough (greater than 4000 characters) 250 264 the input size needs to be set as NCLOB. Alternatively, if the parameter has 251 an `input_size` attribute, then the value of the `input_size` attribute will 265 an `input_size` attribute, then the value of the `input_size` attribute will 252 266 be used instead. Otherwise, no input size will be set for the parameter when 253 267 executing the query. … … 283 297 else: 284 298 return tuple([OracleParam(p, self.charset, True) for p in params]) 285 299 286 300 def _guess_input_sizes(self, params_list): 287 301 if isinstance(params_list[0], dict): … … 304 318 else: 305 319 return [p.smart_str for p in params] 306 320 307 321 def execute(self, query, params=None): 308 322 if params is None: django/branches/gis/django/db/backends/oracle/query.py
r7523 r8215 88 88 included in the query. 89 89 """ 90 90 91 # The `do_offset` flag indicates whether we need to construct 91 92 # the SQL needed to use limit/offset w/Oracle. 92 do_offset = with_limits and (self.high_mark or self.low_mark) 93 do_offset = with_limits and (self.high_mark is not None 94 or self.low_mark) 93 95 94 96 # If no offsets, just return the result of the base class … … 118 120 # extra selection SQL. 119 121 self.extra_select['rn'] = 'ROW_NUMBER() OVER (ORDER BY %s )' % rn_orderby 120 sql, params = super(OracleQuery, self).as_sql(with_limits=False,122 sql, params = super(OracleQuery, self).as_sql(with_limits=False, 121 123 with_col_aliases=True) 122 124 … … 127 129 # Place WHERE condition on `rn` for the desired range. 128 130 result.append('WHERE rn > %d' % self.low_mark) 129 if self.high_mark :131 if self.high_mark is not None: 130 132 result.append('AND rn <= %d' % self.high_mark) 131 133 … … 149 151 _classes[QueryClass] = OracleQuery 150 152 return OracleQuery 151 django/branches/gis/django/db/backends/sqlite3/base.py
r7979 r8215 85 85 return sql 86 86 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 87 93 class DatabaseWrapper(BaseDatabaseWrapper): 88 94 features = DatabaseFeatures() … … 160 166 except (ValueError, TypeError): 161 167 return None 162 return str(getattr(dt, lookup_type))168 return getattr(dt, lookup_type) 163 169 164 170 def _sqlite_date_trunc(lookup_type, dt): django/branches/gis/django/db/backends/util.py
r7279 r8215 1 1 import datetime 2 import md53 2 from time import time 3 4 from django.utils.hashcompat import md5_constructor 4 5 5 6 try: … … 115 116 return name 116 117 117 hash = md5 .md5(name).hexdigest()[:4]118 hash = md5_constructor(name).hexdigest()[:4] 118 119 119 120 return '%s%s' % (name[:length-4], hash) 121 122 def format_number(value, max_digits, decimal_places): 123 """ 124 Formats a number into a string with the requisite number of digits and 125 decimal places. 126 """ 127 return u"%.*f" % (decimal_places, value) django/branches/gis/django/db/models/base.py
r7979 r8215 13 13 from django.core import validators 14 14 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError 15 from django.db.models.fields import AutoField, ImageField , FieldDoesNotExist15 from django.db.models.fields import AutoField, ImageField 16 16 from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField 17 17 from django.db.models.query import delete_objects, Q, CollectedObjects … … 21 21 from django.db.models.loading import register_models, get_model 22 22 from django.dispatch import dispatcher 23 from django.utils.datastructures import SortedDict24 23 from django.utils.functional import curry 25 24 from django.utils.encoding import smart_str, force_unicode, smart_unicode … … 202 201 203 202 for field in fields_iter: 203 rel_obj = None 204 204 if kwargs: 205 205 if isinstance(field.rel, ManyToOneRel): … … 218 218 if rel_obj is None and field.null: 219 219 val = None 220 else:221 try:222 val = getattr(rel_obj, field.rel.get_related_field().attname)223 except AttributeError:224 raise TypeError("Invalid value: %r should be a %s instance, not a %s" %225 (field.name, field.rel.to, type(rel_obj)))226 220 else: 227 221 val = kwargs.pop(field.attname, field.get_default()) 228 222 else: 229 223 val = field.get_default() 230 setattr(self, field.attname, val) 224 # If we got passed a related instance, set it using the field.name 225 # instead of field.attname (e.g. "user" instead of "user_id") so 226 # that the object gets properly cached (and type checked) by the 227 # RelatedObjectDescriptor. 228 if rel_obj: 229 setattr(self, field.name, rel_obj) 230 else: 231 setattr(self, field.attname, val) 231 232 232 233 if kwargs: … … 300 301 if not raw: 301 302 for parent, field in meta.parents.items(): 303 # At this point, parent's primary key field may be unknown 304 # (for example, from administration form which doesn't fill 305 # this field). If so, fill it. 306 if getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None: 307 setattr(self, parent._meta.pk.attname, getattr(self, field.attname)) 308 302 309 self.save_base(raw, parent) 303 310 setattr(self, field.attname, self._get_pk_val(parent._meta)) … … 473 480 474 481 def _save_FIELD_file(self, field, filename, raw_field, save=True): 475 directory = field.get_directory_name() 476 try: # Create the date-based directory if it doesn't exist. 477 os.makedirs(os.path.join(settings.MEDIA_ROOT, directory)) 478 except OSError: # Directory probably already exists. 479 pass 482 # Create the upload directory if it doesn't already exist 483 directory = os.path.join(settings.MEDIA_ROOT, field.get_directory_name()) 484 if not os.path.exists(directory): 485 os.makedirs(directory) 486 elif not os.path.isdir(directory): 487 raise IOError('%s exists and is not a directory' % directory) 480 488 481 489 # Check for old-style usage (files-as-dictionaries). Warn here first … … 495 503 import warnings 496 504 warnings.warn( 497 message = "Representing uploaded files as dictionaries is deprecated. Use django.core.files.uploadedfile.SimpleUploadedFile instead.",505 message = "Representing uploaded files as strings is deprecated. Use django.core.files.uploadedfile.SimpleUploadedFile instead.", 498 506 category = DeprecationWarning, 499 507 stacklevel = 2 django/branches/gis/django/db/models/fields/__init__.py
r8002 r8215 23 23 from django.utils.translation import ugettext_lazy, ugettext as _ 24 24 from django.utils.encoding import smart_unicode, force_unicode, smart_str 25 from django.utils.maxlength import LegacyMaxlength26 25 from django.utils import datetime_safe 27 26 … … 63 62 64 63 class Field(object): 65 # Provide backwards compatibility for the maxlength attribute and66 # argument for this class and all subclasses.67 __metaclass__ = LegacyMaxlength68 69 64 # Designates whether empty strings fundamentally are allowed at the 70 65 # database level. … … 192 187 self.name = name 193 188 self.attname, self.column = self.get_attname_column() 194 self.verbose_name = self.verbose_name or (name and name.replace('_', ' ')) 189 if self.verbose_name is None and name: 190 self.verbose_name = name.replace('_', ' ') 195 191 196 192 def contribute_to_class(self, cls, name): … … 218 214 return getattr(model_instance, self.attname) 219 215 216 def get_db_prep_value(self, value): 217 """Returns field's value prepared for interacting with the database 218 backend. 219 220 Used by the default implementations of ``get_db_prep_save``and 221 `get_db_prep_lookup``` 222 """ 223 return value 224 220 225 def get_db_prep_save(self, value): 221 226 "Returns field's value prepared for saving into a database." 222 return value227 return self.get_db_prep_value(value) 223 228 224 229 def get_db_prep_lookup(self, lookup_type, value): … … 227 232 sql, params = value.as_sql() 228 233 return QueryWrapper(('(%s)' % sql), params) 229 if lookup_type in (' exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'search'):234 if lookup_type in ('regex', 'iregex', 'month', 'day', 'search'): 230 235 return [value] 236 elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'): 237 return [self.get_db_prep_value(value)] 231 238 elif lookup_type in ('range', 'in'): 232 return value239 return [self.get_db_prep_value(v) for v in value] 233 240 elif lookup_type in ('contains', 'icontains'): 234 241 return ["%%%s%%" % connection.ops.prep_for_like_query(value)] … … 246 253 except ValueError: 247 254 raise ValueError("The __year lookup type requires an integer argument") 248 if settings.DATABASE_ENGINE == 'sqlite3': 249 first = '%s-01-01' 250 second = '%s-12-31 23:59:59.999999' 251 elif not connection.features.date_field_supports_time_value and self.get_internal_type() == 'DateField': 252 first = '%s-01-01' 253 second = '%s-12-31' 254 elif not connection.features.supports_usecs: 255 first = '%s-01-01 00:00:00' 256 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) 257 258 else: 258 first = '%s-01-01 00:00:00' 259 second = '%s-12-31 23:59:59.999999' 260 return [first % value, second % value] 259 return connection.ops.year_lookup_bounds(value) 260 261 261 raise TypeError("Field has invalid lookup: %s" % lookup_type) 262 262 … … 289 289 field_objs = [oldforms.SelectField] 290 290 291 params['choices'] = self. flatchoices291 params['choices'] = self.get_flatchoices() 292 292 else: 293 293 field_objs = self.get_manipulator_field_objs() … … 363 363 364 364 def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH): 365 "Returns a list of tuples used as SelectField choices for this field." 365 """Returns choices with a default blank choices included, for use 366 as SelectField choices for this field.""" 366 367 first_choice = include_blank and blank_choice or [] 367 368 if self.choices: … … 377 378 return self.get_choices() 378 379 380 def get_flatchoices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH): 381 "Returns flattened choices with a default blank choice included." 382 first_choice = include_blank and blank_choice or [] 383 return first_choice + list(self.flatchoices) 384 379 385 def _get_val_from_obj(self, obj): 380 386 if obj: … … 409 415 410 416 def _get_flatchoices(self): 417 """Flattened version of choices tuple.""" 411 418 flat = [] 412 for choice, value in self. get_choices_default():419 for choice, value in self.choices: 413 420 if type(value) in (list, tuple): 414 421 flat.extend(value) … … 417 424 return flat 418 425 flatchoices = property(_get_flatchoices) 419 426 420 427 def save_form_data(self, instance, data): 421 428 setattr(instance, self.name, data) … … 450 457 raise validators.ValidationError, _("This value must be an integer.") 451 458 459 def get_db_prep_value(self, value): 460 if value is None: 461 return None 462 return int(value) 463 452 464 def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): 453 465 if not rel: … … 478 490 def __init__(self, *args, **kwargs): 479 491 kwargs['blank'] = True 492 if 'default' not in kwargs and not kwargs.get('null'): 493 kwargs['default'] = False 480 494 Field.__init__(self, *args, **kwargs) 481 495 … … 488 502 if value in ('f', 'False', '0'): return False 489 503 raise validators.ValidationError, _("This value must be either True or False.") 504 505 def get_db_prep_value(self, value): 506 if value is None: 507 return None 508 return bool(value) 490 509 491 510 def get_manipulator_field_objs(self): … … 550 569 raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 551 570 552 def get_db_prep_lookup(self, lookup_type, value):553 if lookup_type in ('range', 'in'):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 = datetime_safe.new_date(value).strftime('%Y-%m-%d')557 else:558 value = smart_unicode(value)559 return Field.get_db_prep_lookup(self, lookup_type, value)560 561 571 def pre_save(self, model_instance, add): 562 572 if self.auto_now or (self.auto_now_add and add): … … 582 592 return self.editable or self.auto_now or self.auto_now_add 583 593 584 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 = datetime_safe.new_date(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) 594 def get_db_prep_value(self, value): 595 # Casts dates into the format expected by the backend 596 return connection.ops.value_to_db_date(self.to_python(value)) 594 597 595 598 def get_manipulator_field_objs(self): … … 620 623 if isinstance(value, datetime.date): 621 624 return datetime.datetime(value.year, value.month, value.day) 625 626 # Attempt to parse a datetime: 627 value = smart_str(value) 628 # split usecs, because they are not recognized by strptime. 629 if '.' in value: 630 try: 631 value, usecs = value.split('.') 632 usecs = int(usecs) 633 except ValueError: 634 raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[ss[.uuuuuu]] format.') 635 else: 636 usecs = 0 637 kwargs = {'microsecond': usecs} 622 638 try: # Seconds are optional, so try converting seconds first. 623 return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6]) 639 return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6], 640 **kwargs) 641 624 642 except ValueError: 625 643 try: # Try without seconds. 626 return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M')[:5]) 644 return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M')[:5], 645 **kwargs) 627 646 except ValueError: # Try without hour/minutes/seconds. 628 647 try: 629 return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3]) 648 return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3], 649 **kwargs) 630 650 except ValueError: 631 raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 632 633 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) 642 643 def get_db_prep_lookup(self, lookup_type, value): 644 if lookup_type in ('range', 'in'): 645 value = [smart_unicode(v) for v in value] 646 else: 647 value = smart_unicode(value) 648 return Field.get_db_prep_lookup(self, lookup_type, value) 651 raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[ss[.uuuuuu]] format.') 652 653 def get_db_prep_value(self, value): 654 # Casts dates into the format expected by the backend 655 return connection.ops.value_to_db_datetime(self.to_python(value)) 649 656 650 657 def get_manipulator_field_objs(self): … … 711 718 decimal places. 712 719 """ 713 num_chars = self.max_digits 714 # Allow for a decimal point 715 if self.decimal_places > 0: 716 num_chars += 1 717 # Allow for a minus sign 718 if value < 0: 719 num_chars += 1 720 721 return u"%.*f" % (self.decimal_places, value) 722 723 def get_db_prep_save(self, value): 724 value = self._format(value) 725 return super(DecimalField, self).get_db_prep_save(value) 726 727 def get_db_prep_lookup(self, lookup_type, value): 728 if lookup_type in ('range', 'in'): 729 value = [self._format(v) for v in value] 730 else: 731 value = self._format(value) 732 return super(DecimalField, self).get_db_prep_lookup(lookup_type, value) 720 # Method moved to django.db.backends.util. 721 # 722 # It is preserved because it is used by the oracle backend 723 # (django.db.backends.oracle.query), and also for 724 # backwards-compatibility with any external code which may have used 725 # this method. 726 from django.db.backends import util 727 return util.format_number(value, self.max_digits, self.decimal_places) 728 729 def get_db_prep_value(self, value): 730 return connection.ops.value_to_db_decimal(self.to_python(value), 731 self.max_digits, self.decimal_places) 733 732 734 733 def get_manipulator_field_objs(self): … … 769 768 return "FileField" 770 769 771 def get_db_prep_ save(self, value):770 def get_db_prep_value(self, value): 772 771 "Returns field's value prepared for saving into a database." 773 772 # Need to convert UploadedFile objects provided via a form to unicode for database insertion … … 910 909 empty_strings_allowed = False 911 910 911 def get_db_prep_value(self, value): 912 if value is None: 913 return None 914 return float(value) 915 912 916 def get_manipulator_field_objs(self): 913 917 return [oldforms.FloatField] … … 957 961 class IntegerField(Field): 958 962 empty_strings_allowed = False 963 def get_db_prep_value(self, value): 964 if value is None: 965 return None 966 return int(value) 967 959 968 def get_manipulator_field_objs(self): 960 969 return [oldforms.IntegerField] … … 1004 1013 raise validators.ValidationError, _("This value must be either None, True or False.") 1005 1014 1015 def get_db_prep_value(self, value): 1016 if value is None: 1017 return None 1018 return bool(value) 1019 1006 1020 def get_manipulator_field_objs(self): 1007 1021 return [oldforms.NullBooleanField] … … 1016 1030 return super(NullBooleanField, self).formfield(**defaults) 1017 1031 1018 class PhoneNumberField( IntegerField):1032 class PhoneNumberField(Field): 1019 1033 def get_manipulator_field_objs(self): 1020 1034 return [oldforms.PhoneNumberField] … … 1098 1112 return "TimeField" 1099 1113 1100 def get_db_prep_lookup(self, lookup_type, value): 1101 if connection.features.time_field_needs_date: 1102 # Oracle requires a date in order to parse. 1103 def prep(value): 1104 if isinstance(value, datetime.time): 1105 value = datetime.datetime.combine(datetime.date(1900, 1, 1), value) 1106 return smart_unicode(value) 1107 else: 1108 prep = smart_unicode 1109 if lookup_type in ('range', 'in'): 1110 value = [prep(v) for v in value] 1111 else: 1112 value = prep(value) 1113 return Field.get_db_prep_lookup(self, lookup_type, value) 1114 def to_python(self, value): 1115 if value is None: 1116 return None 1117 if isinstance(value, datetime.time): 1118 return value 1119 1120 # Attempt to parse a datetime: 1121 value = smart_str(value) 1122 # split usecs, because they are not recognized by strptime. 1123 if '.' in value: 1124 try: 1125 value, usecs = value.split('.') 1126 usecs = int(usecs) 1127 except ValueError: 1128 raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.') 1129 else: 1130 usecs = 0 1131 kwargs = {'microsecond': usecs} 1132 1133 try: # Seconds are optional, so try converting seconds first. 1134 return datetime.time(*time.strptime(value, '%H:%M:%S')[3:6], 1135 **kwargs) 1136 except ValueError: 1137 try: # Try without seconds. 1138 return datetime.time(*time.strptime(value, '%H:%M')[3:5], 1139 **kwargs) 1140 except ValueError: 1141 raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.') 1114 1142 1115 1143 def pre_save(self, model_instance, add): … … 1121 1149 return super(TimeField, self).pre_save(model_instance, add) 1122 1150 1123 def get_db_prep_save(self, value): 1124 # Casts dates into string format for entry into database. 1125 if value is not None: 1126 # MySQL will throw a warning if microseconds are given, because it 1127 # doesn't support microseconds. 1128 if not connection.features.supports_usecs and hasattr(value, 'microsecond'): 1129 value = value.replace(microsecond=0) 1130 if connection.features.time_field_needs_date: 1131 # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field. 1132 if isinstance(value, datetime.time): 1133 value = datetime.datetime(1900, 1, 1, value.hour, value.minute, 1134 value.second, value.microsecond) 1135 elif isinstance(value, basestring): 1136 value = datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6])) 1137 else: 1138 value = smart_unicode(value) 1139 return Field.get_db_prep_save(self, value) 1151 def get_db_prep_value(self, value): 1152 # Casts times into the format expected by the backend 1153 return connection.ops.value_to_db_time(self.to_python(value)) 1140 1154 1141 1155 def get_manipulator_field_objs(self): django/branches/gis/django/db/models/fields/related.py
r8002 r8215 3 3 from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist 4 4 from django.db.models.related import RelatedObject 5 from django.db.models.query import QuerySet 5 6 from django.db.models.query_utils import QueryWrapper 6 from django.utils.text import capfirst7 7 from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _ 8 8 from django.utils.functional import curry 9 from django.utils.encoding import smart_unicode10 9 from django.core import validators 11 10 from django import oldforms … … 25 24 pending_lookups = {} 26 25 27 def add_lazy_relation(cls, field, relation ):26 def add_lazy_relation(cls, field, relation, operation): 28 27 """ 29 28 Adds a lookup on ``cls`` when a related field is defined using a string, … … 47 46 lazy relationships -- then the relation won't be set up until the 48 47 class_prepared signal fires at the end of model initialization. 48 49 operation is the work that must be performed once the relation can be resolved. 49 50 """ 50 51 # Check for recursive relations … … 68 69 model = get_model(app_label, model_name, False) 69 70 if model: 70 field.rel.to = model 71 field.do_related_class(model, cls) 71 operation(field, model, cls) 72 72 else: 73 73 key = (app_label, model_name) 74 value = (cls, field )74 value = (cls, field, operation) 75 75 pending_lookups.setdefault(key, []).append(value) 76 76 … … 80 80 """ 81 81 key = (sender._meta.app_label, sender.__name__) 82 for cls, field in pending_lookups.pop(key, []): 83 field.rel.to = sender 84 field.do_related_class(sender, cls) 82 for cls, field, operation in pending_lookups.pop(key, []): 83 operation(field, sender, cls) 85 84 86 85 dispatcher.connect(do_pending_lookups, signal=signals.class_prepared) … … 110 109 other = self.rel.to 111 110 if isinstance(other, basestring): 112 add_lazy_relation(cls, self, other) 111 def resolve_related_class(field, model, cls): 112 field.rel.to = model 113 field.do_related_class(model, cls) 114 add_lazy_relation(cls, self, other, resolve_related_class) 113 115 else: 114 116 self.do_related_class(other, cls) … … 116 118 def set_attributes_from_rel(self): 117 119 self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name) 118 self.verbose_name = self.verbose_name or self.rel.to._meta.verbose_name 120 if self.verbose_name is None: 121 self.verbose_name = self.rel.to._meta.verbose_name 119 122 self.rel.field_name = self.rel.field_name or self.rel.to._meta.pk.name 120 123 … … 237 240 else: 238 241 params = {'%s__exact' % self.field.rel.field_name: val} 239 rel_obj = self.field.rel.to._default_manager.get(**params) 242 243 # If the related manager indicates that it should be used for 244 # related fields, respect that. 245 rel_mgr = self.field.rel.to._default_manager 246 if getattr(rel_mgr, 'use_for_related_fields', False): 247 rel_obj = rel_mgr.get(**params) 248 else: 249 rel_obj = QuerySet(self.field.rel.to).get(**params) 240 250 setattr(instance, cache_name, rel_obj) 241 251 return rel_obj … … 341 351 manager.add(*value) 342 352 343 def create_many_related_manager(superclass ):353 def create_many_related_manager(superclass, through=False): 344 354 """Creates a manager that subclasses 'superclass' (which is a Manager) 345 355 and adds behavior for many-to-many related objects.""" … … 355 365 <
