Ticket #2443: durationfield.6.diff
File durationfield.6.diff, 8.9 KB (added by , 17 years ago) |
---|
-
django/db/models/fields/__init__.py
686 686 defaults.update(kwargs) 687 687 return super(DecimalField, self).formfield(**defaults) 688 688 689 class DurationProxy(object): 690 def __init__(self, field): 691 self.field_name = field.name 692 693 def __get__(self, instance=None, owner=None): 694 if instance is None: 695 raise AttributeError, "%s can only be accessed from %s instances." % (self.field_name, owner.__name__) 696 if self.field_name not in instance.__dict__: 697 return None 698 return instance.__dict__[self.field_name] 699 700 def __set__(self, instance, value): 701 if value and not isinstance(value, datetime.timedelta): 702 value = datetime.timedelta(seconds=float(value)) 703 instance.__dict__[self.field_name] = value 704 705 class DurationField(Field): 706 def __init__(self, *args, **kwargs): 707 super(DurationField, self).__init__(*args, **kwargs) 708 self.max_digits, self.decimal_places = 20, 6 709 710 def get_internal_type(self): 711 return "DecimalField" 712 713 def contribute_to_class(self, cls, name): 714 super(DurationField, self).contribute_to_class(cls, name) 715 setattr(cls, name, DurationProxy(self)) 716 717 def get_db_prep_save(self, value): 718 if value is None: 719 return None 720 return str(value.days * 24 * 3600 + value.seconds + float(value.microseconds) / 1000000) 721 722 def to_python(self, value): 723 if isinstance(value, datetime.timedelta): 724 return value 725 try: 726 return datetime.timedelta(seconds=float(value)) 727 except (TypeError, ValueError): 728 raise validators.ValidationError('This value must be a real number.') 729 except OverflowError: 730 raise validators.ValidationError('The maximum allowed value is %s' % datetime.timedelta.max) 731 732 def flatten_data(self, follow, obj=None): 733 val = self._get_val_from_obj(obj) 734 if val is None or val is '': 735 return '' 736 return {self.name: self.get_db_prep_save(val)} 737 738 def formfield(self, form_class=forms.DurationField, **kwargs): 739 return super(DurationField, self).formfield(form_class, **kwargs) 740 741 def get_manipulator_field_objs(self): 742 return [curry(oldforms.DecimalField, max_digits=self.max_digits, decimal_places=self.decimal_places)] 743 689 744 class EmailField(CharField): 690 745 def __init__(self, *args, **kwargs): 691 746 kwargs['max_length'] = kwargs.get('max_length', 75) -
django/newforms/fields.py
20 20 from django.utils.encoding import StrAndUnicode, smart_unicode 21 21 22 22 from util import ErrorList, ValidationError 23 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput 23 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput, DurationWidget 24 24 25 25 26 26 __all__ = ( … … 31 31 'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', 32 32 'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField', 33 33 'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', 34 'SplitDateTimeField', 'IPAddressField', 34 'SplitDateTimeField', 'IPAddressField', 'DurationField', 35 35 ) 36 36 37 37 # These values, if given to to_python(), will trigger the self.required check. … … 753 753 754 754 def __init__(self, *args, **kwargs): 755 755 super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs) 756 757 class DurationField(MultiValueField): 758 widget = DurationWidget 759 760 def __init__(self, *args, **kwargs): 761 errors = self.default_error_messages.copy() 762 fields = ( 763 IntegerField(max_value=999999999, min_value=-999999999), 764 IntegerField(label='Hours', max_value=23, min_value=0), 765 IntegerField(label='Minutes', max_value=59, min_value=0), 766 IntegerField(label='Seconds', max_value=59, min_value=0), 767 IntegerField(label='Microseconds', max_value=999999, min_value=0), 768 ) 769 super(DurationField, self).__init__(fields, *args, **kwargs) 770 771 def compress(self, data_list): 772 if data_list == [None] * 5: 773 raise ValidationError(gettext(u'This field is required.')) 774 if data_list: 775 return datetime.timedelta( 776 days=data_list[0] or 0, 777 hours=data_list[1] or 0, 778 minutes=data_list[2] or 0, 779 seconds=data_list[3] or 0, 780 microseconds=data_list[4] or 0, 781 ) 782 return None -
django/newforms/widgets.py
22 22 'FileInput', 'DateTimeInput', 'Textarea', 'CheckboxInput', 23 23 'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect', 24 24 'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget', 25 'DurationWidget', 25 26 ) 26 27 27 28 class Widget(object): … … 450 451 if value: 451 452 return [value.date(), value.time().replace(microsecond=0)] 452 453 return [None, None] 454 455 class DurationWidget(MultiWidget): 456 def __init__(self, attrs=None): 457 attrs = attrs or {} 458 widgets = ( 459 TextInput(attrs=dict(attrs, size=4, maxlength=10, title='Days')), 460 TextInput(attrs=dict(attrs, size=1, maxlength=2, title='Hours')), 461 TextInput(attrs=dict(attrs, size=1, maxlength=2, title='Minutes')), 462 TextInput(attrs=dict(attrs, size=1, maxlength=2, title='Seconds')), 463 TextInput(attrs=dict(attrs, size=5, maxlength=6, title='Microseconds')), 464 ) 465 super(DurationWidget, self).__init__(widgets, attrs) 466 467 def decompress(self, value): 468 if value: 469 hours, seconds = divmod(value.seconds, 3600) 470 minutes, seconds = divmod(seconds, 60) 471 return [value.days, hours, minutes, seconds, value.microseconds] 472 return [None, None, None, None, None] 473 474 def format_output(self, rendered_widgets): 475 return u'%s days, %s : %s : %s . %s' % tuple(rendered_widgets) -
docs/model-api.txt
218 218 219 219 The admin represents this as an ``<input type="text">`` (a single-line input). 220 220 221 ``DurationField`` 222 ~~~~~~~~~~~~~~~~~ 223 224 **New in Django development version** 225 226 A span of time, represented in Python by a ``timedelta`` instance. 227 228 The admin represents this as an ``<input type="text">`` (a single-line input), 229 with its value representing the number of seconds in the duration. Fractional 230 values are allowed, with a millisecond precision. 231 221 232 ``EmailField`` 222 233 ~~~~~~~~~~~~~~ 223 234 -
docs/newforms.txt
1275 1275 permitted in the value, whilst ``decimal_places`` is the maximum number of 1276 1276 decimal places permitted. 1277 1277 1278 ``DurationField`` 1279 ~~~~~~~~~~~~~~~~~ 1280 1281 **New in Django development version** 1282 1283 * Default widget: ``DurationWidget`` 1284 * Empty value: ``None`` 1285 * Normalizes to: A Python ``datetime.timedelta`` object 1286 * Validates that the given value is a length of time, such as 24 hours in a 1287 day, 60 minutes in an hour, and 60 seconds in a minute. 1288 1289 A span of time, represented in Python by a ``timedelta`` instance. 1290 1291 The admin represents this as an ``<input type="text">`` (a single-line input), 1292 with its value representing the number of seconds in the duration. Fractional 1293 values are allowed, with a millisecond precision. 1294 1278 1295 ``EmailField`` 1279 1296 ~~~~~~~~~~~~~~ 1280 1297 … … 1618 1635 ``MultiWidget`` Wrapper around multiple other widgets 1619 1636 ``SplitDateTimeWidget`` Wrapper around two ``TextInput`` widgets: 1620 1637 one for the Date, and one for the Time. 1638 ``DurationWidget`` A set of 5 ``TextInput`` widgets arranged 1639 as ``[ ] days, [ ]:[ ]:[ ].[ ]`` 1621 1640 ============================ =========================================== 1622 1641 1623 **New in Django development version:** The ``DateTimeInput`` has been added1624 since the last release.1642 **New in Django development version:** The ``DateTimeInput`` and 1643 ``DurationWidget`` have been added since the last release. 1625 1644 1626 1645 Specifying widgets 1627 1646 ------------------