Ticket #4004: FloatField.diff

File FloatField.diff, 5.8 KB (added by tonnzor <tonn81@…>, 17 years ago)

FloatField

  • fields.py

     
    1111import time
    1212
    1313__all__ = (
    14     'Field', 'CharField', 'IntegerField',
     14    'Field', 'CharField', 'IntegerField', 'FloatField',
    1515    'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
    1616    'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
    1717    'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
     
    132132            raise ValidationError(gettext(u'Ensure this value is greater than or equal to %s.') % self.min_value)
    133133        return value
    134134
     135class FloatField(Field):
     136    def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
     137        self.max_value, self.min_value, self.max_digits, self.decimal_places = max_value, min_value, max_digits, decimal_places
     138        super(FloatField, self).__init__(*args, **kwargs)
     139
     140    def clean(self, value):
     141        """
     142        Validates that float() can be called on the input. Returns the result
     143        of float(). Returns None for empty values.
     144        """
     145        super(FloatField, self).clean(value)
     146        if value in EMPTY_VALUES:
     147            return None
     148        value = str(value).replace(',', '.')  # "," is used as fractional part separator in some languages (Russian, etc.)
     149        value = value.strip()  # remove useless spaces
     150        value = re.sub('^-\s+', '-', value)
     151        value = re.sub('\s*\.\s*', '.', value)
     152        try:
     153            value = float(value)
     154        except (ValueError, TypeError):
     155            raise ValidationError(gettext(u'Enter a number.'))
     156        if self.max_value is not None and value > self.max_value:
     157            raise ValidationError(gettext(u'Ensure this value is less than or equal to %s.') % self.max_value)
     158        if self.min_value is not None and value < self.min_value:
     159            raise ValidationError(gettext(u'Ensure this value is greater than or equal to %s.') % self.min_value)
     160        if self.decimal_places is not None:
     161            regex = (r'\.\d{1,%d}$' % self.decimal_places) if self.decimal_places > 0 else r'\.0$'
     162            regex = re.compile(regex)
     163            if not regex.search(str(value)):
     164                raise ValidationError(gettext(u"Ensure this value's fractional part has at most %d digits") % self.max_digits)
     165        if self.max_digits is not None and self.decimal_places is not None:
     166            regex = r'^[-]?\d{1,%d}\.' % (self.max_digits - self.decimal_places)
     167            regex = re.compile(regex)
     168            if not regex.search(str(value)):
     169                raise ValidationError(gettext(u"Ensure this value's sharp part has at most %d digits") % (self.max_digits - self.decimal_places))
     170        elif self.max_digits is not None:
     171            regex = r'^[-]?\d{1,%d}$' % self.max_digits
     172            regex = re.compile(regex)
     173            value_sams_trailing_zero = re.sub('\.(0$)?', '', str(value))
     174            if not regex.search(value_sams_trailing_zero):
     175                raise ValidationError(gettext(u'Ensure this value has at most %d digits (including sharp part)') % self.max_digits)
     176        return value
     177
     178
    135179DEFAULT_DATE_INPUT_FORMATS = (
    136180    '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
    137181    '%b %d %Y', '%b %d, %Y',            # 'Oct 25 2006', 'Oct 25, 2006'
  • test_floatfield.py

     
     1import django.newforms as forms
     2from django.newforms.util import ValidationError
     3from copy import copy
     4import unittest
     5
     6class TestFloatFieldValidation(unittest.TestCase):
     7   
     8    def mutate_data(self, data):
     9        for row in copy(data):
     10            if row[0].startswith('0.'):
     11                data.append((row[0][1:], row[1], row[2]))
     12        for row in copy(data):
     13            if not row[0].startswith('-'):
     14                data.append(('-' + row[0], row[1], row[2]))
     15        for row in copy(data):
     16            if 0 > row[0].find('.'):
     17                data.append((row[0] + '.0', row[1], row[2]))
     18
     19    def mutate_data_dots(self, data):
     20        for row in copy(data):
     21            if 0 <= row[0].find('.'):
     22                data.append((row[0].replace('.', ','), row[1], row[2]))
     23
     24    def setUp(self):
     25        self.valid_data = [
     26            ('000',   None, None),
     27            ('100',   None, None),
     28            (' 100 ',   None, None),
     29            ('0.364', None, None),
     30       
     31            ('100',   3, None),
     32            ('0.364', 4, None),
     33       
     34            ('100',   None, 0),
     35            ('0.364', None, 3),
     36       
     37            ('100',   3, 0),
     38            ('0.364', 4, 3),
     39            ]
     40
     41        self.invalid_data = [
     42            ('sda',     None, None),
     43            ('1,000.0', None, None),
     44            ('--10',    None, None),
     45            ('10-20',   None, None),
     46            ]
     47
     48        self.mutate_data(self.valid_data)
     49        self.mutate_data_dots(self.valid_data)
     50        self.mutate_data(self.invalid_data)
     51
     52    def test_valid_values_passes(self):
     53        for text, max_digits, decimal_places in self.valid_data:
     54            field = forms.FloatField(max_digits = max_digits, decimal_places = decimal_places)
     55            try:
     56                field.clean(text)
     57            except ValidationError, e:
     58                self.fail('%s : %s' % (text, e))
     59
     60    def test_invalid_values_excepts(self):
     61        for text, max_digits, decimal_places in self.invalid_data:
     62            field = forms.FloatField(max_digits = max_digits, decimal_places = decimal_places)
     63            self.assertRaises(ValidationError, field.clean, text)
     64
     65suite = unittest.TestLoader().loadTestsFromTestCase(TestFloatFieldValidation)
     66unittest.TextTestRunner(verbosity=2).run(suite)
     67
Back to Top