Commits

Felipe Prenholato committed 04467c7 Merge

Merge upstream

Comments (0)

Files changed (7)

 9b3cdbb15d0276f49ddb77e2a03f3f6f0546a940 0.6.5
 8c37b19265e4427ef00b4e9e8ffc0a0abcc7011c 0.6.6
 8626c421cc0b2526af1bea4ead20dc39be2f796c 0.6.7
+f3664b91e89fd92f90974485a7a93511f6cb481a 0.6.8

timedelta/VERSION

-0.6.7
+0.6.8

timedelta/fields.py

 from django.db import models
+from django.core.exceptions import ValidationError
 
 from collections import defaultdict
 import datetime
     
     description = "A datetime.timedelta object"
     
+    def __init__(self, *args, **kwargs):
+        self._min_value = kwargs.pop('min_value', None)
+        self._max_value = kwargs.pop('max_value', None)
+        super(TimedeltaField, self).__init__(*args, **kwargs)
+    
     def to_python(self, value):
         if (value is None) or isinstance(value, datetime.timedelta):
             return value
         if isinstance(value, int):
             return datetime.timedelta(seconds=value)
         if value == "":
-            return None
+            if self.null:
+                return None
+            else:
+                return datetime.timedelta(0)
         return parse(value)
     
     def get_prep_value(self, value):
         defaults.update(kwargs)
         return super(TimedeltaField, self).formfield(*args, **defaults)
     
+    def validate(self, value, model_instance):
+        super(TimedeltaField, self).validate(value, model_instance)
+        if self._min_value is not None:
+            if self._min_value > value:
+                raise ValidationError('Less than minimum allowed value')
+        if self._max_value is not None:
+            if self._max_value < value:
+                raise ValidationError('More than maximum allowed value')
+    
     def value_to_string(self, obj):
         value = self._get_val_from_obj(obj)
         return unicode(value)

timedelta/helpers.py

     """
     if string == "":
         raise TypeError("'%s' is not a valid time interval" % string)
-    # This is the format we get from sometimes Postgres, and from serialization
-    d = re.match(r'((?P<days>\d+) days?,? )?(?P<hours>\d+):'
-                 r'(?P<minutes>\d+)(:(?P<seconds>\d+))?',
+    # This is the format we get from sometimes Postgres, sqlite,
+    # and from serialization
+    d = re.match(r'^((?P<days>\d+) days?,? )?(?P<hours>\d+):'
+                 r'(?P<minutes>\d+)(:(?P<seconds>\d+(\.\d+)?))?$',
                  unicode(string))
     if d:
         d = d.groupdict(0)

timedelta/templatetags/decimal_hours.py

 
 @register.filter(name='decimal_hours')
 def decimal_hours(value, decimal_places=None):
+    if value is None:
+        return value
     return dh(value, decimal_places)

timedelta/templatetags/timedelta.py

 
 @register.filter(name='timedelta')
 def timedelta(value, display="long"):
+    if value is None:
+        return value
     return nice_repr(value, display)
 
 @register.filter(name='iso8601')
 def iso8601(value):
+    if value is None:
+        return value
     return iso8601_repr(value)
 
 @register.filter(name='total_seconds')
 def total_seconds(value):
+    if value is None:
+        return value
     return _total_seconds(value)
 
 @register.filter(name='total_seconds_sort')
 def total_seconds_sort(value, places=10):
+    if value is None:
+        return value
     return ("%0" + str(places) + "i") % _total_seconds(value)
 
 @register.filter(name='as_hours')

timedelta/tests.py

+from django.db import models
+from django.core.exceptions import ValidationError
 from unittest import TestCase
+
 import datetime
+
 from forms import TimedeltaFormField
+from fields import TimedeltaField
 from widgets import TimedeltaWidget
 from helpers import *
 
         u'<input type="text" name="" value="3 days, 12 hours" />'
         """
 
+class MinMaxTestModel(models.Model):
+    min = TimedeltaField(min_value=datetime.timedelta(1))
+    max = TimedeltaField(max_value=datetime.timedelta(1))
+    minmax = TimedeltaField(min_value=datetime.timedelta(1), max_value=datetime.timedelta(7))
+    
+class TimedeltaModelFieldTest(TestCase):
+    def test_validate(self):
+        test = MinMaxTestModel(
+            min=datetime.timedelta(1),
+            max=datetime.timedelta(1),
+            minmax=datetime.timedelta(1)
+        )
+        test.full_clean() # This should have met validation requirements.
+        
+        test.min = datetime.timedelta(hours=23)
+        self.assertRaises(ValidationError, test.full_clean)
+        
+        test.min = datetime.timedelta(hours=25)
+        test.full_clean()
+        
+        test.max = datetime.timedelta(11)
+        self.assertRaises(ValidationError, test.full_clean)
+        
+        test.max = datetime.timedelta(hours=20)
+        test.full_clean()
+        
+        test.minmax = datetime.timedelta(0)
+        self.assertRaises(ValidationError, test.full_clean)
+        test.minmax = datetime.timedelta(22)
+        self.assertRaises(ValidationError, test.full_clean)
+        test.minmax = datetime.timedelta(6, hours=23, minutes=59, seconds=59)
+        test.full_clean()
+
 class TimedeltaFormFieldTest(TestCase):
     def test_clean(self):
         """
         datetime.timedelta(1)
         >>> t.clean('1 day, 0:00:00')
         datetime.timedelta(1)
+        >>> t.clean('1 day, 8:42:42.342')
+        datetime.timedelta(1, 31362, 342000)
+        >>> t.clean('3 days, 8:42:42.342161')
+        datetime.timedelta(3, 31362, 342161)
+        >>> t.clean('3 days, 8:42:42.3.42161')
+        Traceback (most recent call last):
+        ValidationError: [u'Enter a valid time span: e.g. "3 days, 4 hours, 2 minutes"']
         >>> t.clean('5 day, 8:42:42')
         datetime.timedelta(5, 31362)
         >>> t.clean('1 days')
         Traceback (most recent call last):
         ValidationError: [u'Enter a valid time span: e.g. "3 days, 4 hours, 2 minutes"']
         """
+    
 
 class TimedeltaHelpersTest(TestCase):
     def test_parse(self):