Django

Code

Ticket #2443: durationfield.4.diff

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

New patch, complete with documentation

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

    old new  
    636676        defaults.update(kwargs) 
    637677        return super(DecimalField, self).formfield(**defaults) 
    638678 
     679class DurationField(Field): 
     680    max_digits, decimal_places = 20, 6 
     681 
     682    def get_internal_type(self): 
     683        return "DecimalField" 
     684 
     685    def contribute_to_class(self, cls, name): 
     686        super(DurationField, self).contribute_to_class(cls, name) 
     687        setattr(cls, name, self.lazy_attribute(datetime.timedelta, self.create)) 
     688 
     689    def get_db_prep_save(self, value): 
     690        return str(value.days * 24 * 3600 + value.seconds + float(value.microseconds) / 1000000) 
     691 
     692    def to_python(self, value): 
     693        if isinstance(value, datetime.timedelta): 
     694            return value 
     695        try: 
     696            return datetime.timedelta(seconds=float(value)) 
     697        except (TypeError, ValueError): 
     698            raise validators.ValidationError('This value must be a real number.') 
     699        except OverflowError: 
     700            raise validators.ValidationError('The maximum allowed value is %s' % datetime.timedelta.max) 
     701 
     702    def create(self, value): 
     703        return datetime.timedelta(seconds=float(value) or 0) 
     704     
     705    def flatten_data(self, follow, obj=None): 
     706        val = self._get_val_from_obj(obj) 
     707        if val is None or val is '': 
     708            return '' 
     709        return {self.attname: self.get_db_prep_save(val)} 
     710 
     711    def formfield(self, form_class=forms.SplitDurationField, **kwargs): 
     712        return super(DurationField, self).formfield(form_class, **kwargs) 
     713 
     714    def get_manipulator_field_objs(self): 
     715        return [curry(oldforms.DecimalField, max_digits=self.max_digits, decimal_places=self.decimal_places)] 
     716 
    639717class EmailField(CharField): 
    640718    def __init__(self, *args, **kwargs): 
    641719        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', 'FloatField', 'DecimalField', 
    23     'SplitDateTimeField', 
     23    'SplitDateTimeField', 'SplitDurationField', 
    2424) 
    2525 
    2626# These values, if given to to_python(), will trigger the self.required check. 
     
    560560        if data_list: 
    561561            return datetime.datetime.combine(*data_list) 
    562562        return None 
     563 
     564class SplitDurationField(MultiValueField): 
     565    widget = SplitDurationWidget 
     566 
     567    def __init__(self, *args, **kwargs): 
     568        fields = ( 
     569            IntegerField(label='Days', max_value=999999999, min_value=-999999999), 
     570            IntegerField(label='Hours', max_value=23, min_value=0), 
     571            IntegerField(label='Minutes', max_value=59, min_value=0), 
     572            IntegerField(label='Seconds', max_value=59, min_value=0), 
     573            IntegerField(label='Microseconds', max_value=999999, min_value=0), 
     574        ) 
     575        super(SplitDurationField, self).__init__(fields, *args, **kwargs) 
     576 
     577    def compress(self, data_list): 
     578        if data_list == [None] * 5: 
     579            raise ValidationError(gettext(u'This field is required.')) 
     580        if data_list: 
     581            return datetime.timedelta( 
     582                days=data_list[0] or 0, 
     583                hours=data_list[1] or 0, 
     584                minutes=data_list[2] or 0, 
     585                seconds=data_list[3] or 0, 
     586                microseconds=data_list[4] or 0, 
     587            ) 
     588        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) 
  • docs/model-api.txt

    old new  
    213213 
    214214The admin represents this as an ``<input type="text">`` (a single-line input). 
    215215 
     216``DurationField`` 
     217~~~~~~~~~~~~~~~~~ 
     218 
     219**New in Django development version** 
     220 
     221A span of time, represented in Python by a ``timedelta`` instance. 
     222 
     223The admin represents this as an ``<input type="text">`` (a single-line input), 
     224with its value representing the number of seconds in the duration. Fractional 
     225values are allowed, with a millisecond precision. 
     226 
    216227``EmailField`` 
    217228~~~~~~~~~~~~~~ 
    218229