Ticket #2443: durationfield.3.diff

File durationfield.3.diff, 5.4 KB (added by Marty Alchin <gulopine@…>, 8 years ago)

Complete patch with widget, supporting oldforms and newforms, including newforms-admin

  • django/db/models/fields/__init__.py

     
    573573        defaults.update(kwargs)
    574574        return super(DateTimeField, self).formfield(**defaults)
    575575
     576class DurationField(Field):
     577    max_digits, decimal_places = 20, 6
     578
     579    def get_internal_type(self):
     580        return "FloatField"
     581
     582    def get_db_prep_save(self, value):
     583        return str(value.days * 24 * 3600 + value.seconds + float(value.microseconds) / 1000000)
     584
     585    def to_python(self, value):
     586        if isinstance(value, datetime.timedelta):
     587            return value
     588        try:
     589            return datetime.timedelta(seconds=float(value))
     590        except (TypeError, ValueError):
     591            raise validators.ValidationError('This value must be a real number.')
     592        except OverflowError:
     593            raise validators.ValidationError('The maximum allowed value is %s' % datetime.timedelta.max)
     594
     595    def coerce(self, value):
     596        return self.to_python(value)
     597
     598    def flatten_data(self, follow, obj=None):
     599        val = self._get_val_from_obj(obj)
     600        return {self.attname: (val is not None and self.get_db_prep_save(val) or '')}
     601
     602    def formfield(self, form_class=forms.SplitDurationField, **kwargs):
     603        return super(DurationField, self).formfield(form_class, **kwargs)
     604
     605    def get_manipulator_field_objs(self):
     606        return [curry(oldforms.FloatField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
     607
    576608class EmailField(CharField):
    577609    def __init__(self, *args, **kwargs):
    578610        kwargs['maxlength'] = 75
  • django/newforms/fields.py

     
    1010from django.utils.encoding import smart_unicode
    1111
    1212from util import ErrorList, ValidationError
    13 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple
     13from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, SplitDurationWidget
    1414
    1515__all__ = (
    1616    'Field', 'CharField', 'IntegerField',
     
    2020    'RegexField', 'EmailField', 'URLField', 'BooleanField',
    2121    'ChoiceField', 'NullBooleanField', 'MultipleChoiceField',
    2222    'ComboField', 'MultiValueField',
    23     'SplitDateTimeField',
     23    'SplitDateTimeField', 'SplitDurationField',
    2424)
    2525
    2626# These values, if given to to_python(), will trigger the self.required check.
     
    494494        if data_list:
    495495            return datetime.datetime.combine(*data_list)
    496496        return None
     497
     498class SplitDurationField(MultiValueField):
     499    widget = SplitDurationWidget
     500
     501    def __init__(self, *args, **kwargs):
     502        fields = (
     503            IntegerField(label='Days', max_value=999999999, min_value=-999999999),
     504            IntegerField(label='Hours', max_value=23, min_value=0),
     505            IntegerField(label='Minutes', max_value=59, min_value=0),
     506            IntegerField(label='Seconds', max_value=59, min_value=0),
     507            IntegerField(label='Microseconds', max_value=999999, min_value=0),
     508        )
     509        super(SplitDurationField, self).__init__(fields, *args, **kwargs)
     510
     511    def compress(self, data_list):
     512        if data_list == [None] * 5:
     513            raise ValidationError(gettext(u'This field is required.'))
     514        if data_list:
     515            return datetime.timedelta(
     516                days=data_list[0] or 0,
     517                hours=data_list[1] or 0,
     518                minutes=data_list[2] or 0,
     519                seconds=data_list[3] or 0,
     520                microseconds=data_list[4] or 0,
     521            )
     522        return None
  • django/newforms/widgets.py

     
    2121    'FileInput', 'Textarea', 'CheckboxInput',
    2222    'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
    2323    'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
     24    'SplitDurationWidget',
    2425)
    2526
    2627class Widget(object):
     
    374375        if value:
    375376            return [value.date(), value.time()]
    376377        return [None, None]
     378
     379class SplitDurationWidget(MultiWidget):
     380    def __init__(self, attrs=None):
     381        attrs = attrs or {}
     382        widgets = (
     383            TextInput(attrs=dict(attrs, size=4, maxlength=10, title='Days')),
     384            TextInput(attrs=dict(attrs, size=1, maxlength=2, title='Hours')),
     385            TextInput(attrs=dict(attrs, size=1, maxlength=2, title='Minutes')),
     386            TextInput(attrs=dict(attrs, size=1, maxlength=2, title='Seconds')),
     387            TextInput(attrs=dict(attrs, size=5, maxlength=6, title='Microseconds')),
     388        )
     389        super(SplitDurationWidget, self).__init__(widgets, attrs)
     390
     391    def decompress(self, value):
     392        if value:
     393            hours, seconds = divmod(value.seconds, 3600)
     394            minutes, seconds = divmod(seconds, 60)
     395            return [value.days, hours, minutes, seconds, value.microseconds]
     396        return [None, None, None, None, None]
     397
     398    def format_output(self, rendered_widgets):
     399        return u'%s days, %s : %s : %s . %s' % tuple(rendered_widgets)
Back to Top