Ticket #2443: durationfield-new.diff
File durationfield-new.diff, 6.7 KB (added by , 16 years ago) |
---|
-
django/db/models/fields/__init__.py
636 636 defaults.update(kwargs) 637 637 return super(DecimalField, self).formfield(**defaults) 638 638 639 class DurationProxy(object): 640 def __init__(self, field): 641 self.field_name = field.name 642 643 def __get__(self, instance=None, owner=None): 644 if instance is None: 645 raise AttributeError, "%s can only be accessed from %s instances." % (self.field_name, owner.__name__) 646 if self.field_name not in instance.__dict__: 647 return None 648 return instance.__dict__[self.field_name] 649 650 def __set__(self, instance, value): 651 if value and not isinstance(value, datetime.timedelta): 652 value = datetime.timedelta(microseconds=float(value)) 653 instance.__dict__[self.field_name] = value 654 655 class DurationField(Field): 656 def __init__(self, *args, **kwargs): 657 super(DurationField, self).__init__(*args, **kwargs) 658 self.max_digits, self.decimal_places = 20, 6 659 660 def get_internal_type(self): 661 return "DecimalField" 662 663 def contribute_to_class(self, cls, name): 664 super(DurationField, self).contribute_to_class(cls, name) 665 setattr(cls, name, DurationProxy(self)) 666 667 def get_db_prep_save(self, value): 668 if value is None: 669 return None 670 if not isinstance(value, datetime.timedelta): 671 value = datetime.timedelta(microseconds=value) 672 return connection.ops.value_to_db_decimal(value.days * 24 * 3600 * 1000000 + value.seconds * 1000000 + value.microseconds, 20, 0) # max value 86399999999999999999 microseconds 673 674 def to_python(self, value): 675 if isinstance(value, datetime.timedelta): 676 return value 677 try: 678 return datetime.timedelta(microseconds=float(value)) 679 except (TypeError, ValueError): 680 raise exceptions.ValidationError('The value must be an integer.') 681 except OverflowError: 682 raise exceptions.ValidationError('The maximum allowed value is %s' % datetime.timedelta.max) 683 684 def formfield(self, form_class=forms.DurationField, **kwargs): 685 return super(DurationField, self).formfield(form_class, **kwargs) 686 639 687 class EmailField(CharField): 640 688 def __init__(self, *args, **kwargs): 641 689 kwargs['max_length'] = kwargs.get('max_length', 75) -
django/forms/fields.py
26 26 import django.core.exceptions 27 27 from django.utils.translation import ugettext_lazy as _ 28 28 from django.utils.encoding import smart_unicode, smart_str 29 from django.utils.datastructures import SortedDict 29 30 30 31 from util import ErrorList, ValidationError 31 32 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget … … 40 41 'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField', 41 42 'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', 42 43 'SplitDateTimeField', 'IPAddressField', 'FilePathField', 'SlugField', 43 'TypedChoiceField' 44 'TypedChoiceField', 'DurationField', 44 45 ) 45 46 46 47 # These values, if given to to_python(), will trigger the self.required check. … … 885 886 return datetime.datetime.combine(*data_list) 886 887 return None 887 888 889 class DurationField(Field): 890 default_error_messages = { 891 'invalid': _(u'Enter a valid duration.'), 892 'min_value': _(u'Ensure this value is greater than or equal to %(min)s.'), 893 'max_value': _(u'Ensure this value is less than or equal to %(max)s.'), 894 } 895 values_in_microseconds = SortedDict(( 896 ('y', 31556925993600), # 52.177457 * (7*24*60*60*1000*1000) 897 ('m', 2629743828768), # 4.34812141 * (7*24*60*60*1000*1000) 898 ('w', 604800000000), # 7*24*60*60*1000*1000 899 ('d', 86400000000), # 24*60*60*1000*1000 900 ('h', 3600000000), # 60*60*1000*1000 901 ('min', 60000000), # 60*1000*1000 902 ('s', 1000000), # 1000*1000 903 ('ms', 1000), 904 ('mis', 1), 905 )) 906 907 def __init__(self, min_value=None, max_value=None, *args, **kwargs): 908 super(DurationField, self).__init__(*args, **kwargs) 909 self.min_value, self.max_value = min_value, max_value 910 911 def to_timedelta(self, value): 912 """ 913 Takes an Unicode value and converts it to a datetime.timedelta object. 914 1y 7m 6w 3d 18h 30min 23s 10ms 150mis => 915 1 year 7 months 6 weeks 3 days 18 hours 30 minutes 23 seconds 10 milliseconds 150 microseconds 916 => datetime.timedelta(624, 6155, 805126) 917 """ 918 if not value: 919 return datetime.timedelta(microseconds=0) 920 921 pairs = [] 922 for b in value.lower().split(): 923 for index, char in enumerate(b): 924 if not char.isdigit(): 925 pairs.append((b[:index], b[index:])) #digits, letters 926 break 927 if not pairs: 928 raise ValidationError(self.error_messages['invalid']) 929 930 microseconds = 0 931 for digits, chars in pairs: 932 if not digits or not chars: 933 raise ValidationError(self.error_messages['invalid']) 934 microseconds += int(digits) * self.values_in_microseconds[chars] 935 936 return datetime.timedelta(microseconds=microseconds) 937 938 def from_timedelta(self, value): 939 if not value: 940 return u"0 sec" 941 vals = [] 942 mis = value.days * 24 * 3600 * 1000000 + value.seconds * 1000000 + value.microseconds 943 for k in self.values_in_microseconds: 944 if mis >= self.values_in_microseconds[k]: 945 diff, mis = divmod(mis, self.values_in_microseconds[k]) 946 vals.append("%d%s" % (diff, k)) 947 return u" ".join(vals) 948 949 def clean(self, value): 950 "Validates max_value and min_value. Returns a datetime.timedelta object." 951 value = self.to_timedelta(value) 952 953 if self.max_value is not None and value > self.max_value: 954 raise ValidationError(self.error_messages['max_value'] % {'max': self.max_value}) 955 956 if self.min_value is not None and value < self.min_value: 957 raise ValidationError(self.error_messages['min_value'] % {'min': self.min_value}) 958 959 return value 960 961 888 962 ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$') 889 963 890 964 class IPAddressField(RegexField):