Django

Code

Ticket #2443: durationfield.3.diff

File durationfield.3.diff, 5.4 kB (added by Marty Alchin <gulopine@gamemusic.org>, 3 years ago)

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

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

    old new  
    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

    old new  
    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

    old new  
    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)