Ticket #16306: 16306.diff
File 16306.diff, 12.1 KB (added by , 13 years ago) |
---|
-
django/forms/fields.py
diff --git a/django/forms/fields.py b/django/forms/fields.py index 113a5aa..e12936c 100644
a b __all__ = ( 40 40 ) 41 41 42 42 43 class ValidatorAttribute(object): 44 """ 45 A descriptor used to dynamically update a field's validators based on a 46 single value. 47 48 .. attribute:: create_func 49 50 A function used to create a validator. It should take two arguments, 51 the object instance and a value. 52 53 When a value is set to this descriptor, this function is executed and 54 the validator it returns (if any) is added to the field's 55 :attr:`~Field.validators` list. 56 57 If this descriptor had previously set a validator, it will be removed 58 from the field's ``validators`` list. 59 60 .. attribute:: clean_func 61 62 An optional function which can modify the incoming value before setting 63 it. The function should take the same two arguments as 64 :attr:`create_func`. 65 """ 66 67 def __init__(self, create_func, clean_func=None): 68 """ 69 :param create_func: A function that creates a validator, sets 70 :attr:`create_func`. 71 :param clean_func: An optional function which can be used to clean the 72 incoming value. Sets :attr:`clean_func`. 73 """ 74 self.create_func = create_func 75 self.clean_func = clean_func 76 self.value = None 77 self.validator = None 78 79 def __get__(self, obj, obj_type): 80 return self.value 81 82 def __set__(self, obj, value): 83 if self.clean_func: 84 value = self.clean_func(obj, value) 85 self.value = value 86 if value is None: 87 new_validator = None 88 else: 89 new_validator = self.create_func(obj, value) 90 if new_validator is self.validator: 91 return 92 if self.validator: 93 try: 94 obj.validators.remove(self.validator) 95 except ValueError: 96 pass 97 if new_validator: 98 obj.validators.append(new_validator) 99 self.validator = new_validator 100 43 101 class Field(object): 44 102 widget = TextInput # Default widget to use when rendering this type of Field. 45 103 hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden". … … class Field(object): 180 238 181 239 class CharField(Field): 182 240 def __init__(self, max_length=None, min_length=None, *args, **kwargs): 183 self.max_length, self.min_length = max_length, min_length184 241 super(CharField, self).__init__(*args, **kwargs) 185 if min_length is not None: 186 self.validators.append(validators.MinLengthValidator(min_length)) 187 if max_length is not None: 188 self.validators.append(validators.MaxLengthValidator(max_length)) 242 self.max_length, self.min_length = max_length, min_length 243 244 max_length = ValidatorAttribute( 245 create_func=lambda self, val: validators.MaxLengthValidator(val) 246 ) 247 248 min_length = ValidatorAttribute( 249 create_func=lambda self, val: validators.MinLengthValidator(val) 250 ) 189 251 190 252 def to_python(self, value): 191 253 "Returns a Unicode object." … … class IntegerField(Field): 206 268 } 207 269 208 270 def __init__(self, max_value=None, min_value=None, *args, **kwargs): 209 self.max_value, self.min_value = max_value, min_value210 271 super(IntegerField, self).__init__(*args, **kwargs) 272 self.max_value, self.min_value = max_value, min_value 273 274 max_value = ValidatorAttribute( 275 create_func=lambda self, val: validators.MaxValueValidator(val) 276 ) 211 277 212 if max_value is not None: 213 self.validators.append(validators.MaxValueValidator(max_value)) 214 if min_value is not None: 215 self.validators.append(validators.MinValueValidator(min_value)) 278 min_value = ValidatorAttribute( 279 create_func=lambda self, val: validators.MinValueValidator(val) 280 ) 216 281 217 282 def to_python(self, value): 218 283 """ … … class DecimalField(Field): 261 326 'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.') 262 327 } 263 328 264 def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs): 329 def __init__(self, max_value=None, min_value=None, max_digits=None, 330 decimal_places=None, *args, **kwargs): 331 super(DecimalField, self).__init__(*args, **kwargs) 265 332 self.max_value, self.min_value = max_value, min_value 266 333 self.max_digits, self.decimal_places = max_digits, decimal_places 267 Field.__init__(self, *args, **kwargs)268 334 269 if max_value is not None: 270 self.validators.append(validators.MaxValueValidator(max_value)) 271 if min_value is not None: 272 self.validators.append(validators.MinValueValidator(min_value)) 335 max_value = ValidatorAttribute( 336 create_func=lambda self, val: validators.MaxValueValidator(val) 337 ) 338 339 min_value = ValidatorAttribute( 340 create_func=lambda self, val: validators.MinValueValidator(val) 341 ) 273 342 274 343 def to_python(self, value): 275 344 """ … … class RegexField(CharField): 439 508 error_messages['invalid'] = error_message 440 509 kwargs['error_messages'] = error_messages 441 510 super(RegexField, self).__init__(max_length, min_length, *args, **kwargs) 511 self.regex = regex 512 513 def clean_regex_value(self, regex): 442 514 if isinstance(regex, basestring): 443 515 regex = re.compile(regex) 444 self.regex = regex 445 self.validators.append(validators.RegexValidator(regex=regex)) 516 return regex 517 518 regex = ValidatorAttribute( 519 create_func=lambda obj, value: validators.RegexValidator(value), 520 clean_func=clean_regex_value 521 ) 446 522 447 523 class EmailField(CharField): 448 524 default_error_messages = { -
tests/regressiontests/forms/tests/fields.py
diff --git a/tests/regressiontests/forms/tests/fields.py b/tests/regressiontests/forms/tests/fields.py index ad8d1d9..17da030 100644
a b class FieldsTests(TestCase): 109 109 self.assertEqual(f.max_length, None) 110 110 self.assertEqual(f.min_length, 10) 111 111 112 def test_charfield_validator_attributes(self): 113 f = CharField(min_length=2, max_length=4) 114 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value has at least 2 characters (it has 1).']", f.clean, '1') 115 self.assertEqual(u'123', f.clean('123')) 116 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value has at most 4 characters (it has 5).']", f.clean, '12345') 117 118 f.min_length = 6 119 f.max_length = 8 120 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value has at least 6 characters (it has 3).']", f.clean, '123') 121 self.assertEqual(u'1234567', f.clean('1234567')) 122 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value has at most 8 characters (it has 9).']", f.clean, '123456789') 123 124 f.min_length = None 125 f.max_length = None 126 self.assertEqual(u'1', f.clean('1')) 127 self.assertEqual(u'123456789', f.clean('123456789')) 128 112 129 # IntegerField ################################################################ 113 130 114 131 def test_integerfield_1(self): … … class FieldsTests(TestCase): 180 197 self.assertEqual(f.max_value, 20) 181 198 self.assertEqual(f.min_value, 10) 182 199 200 def test_integerfield_validator_attributes(self): 201 f = IntegerField(min_value=2, max_value=4) 202 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is greater than or equal to 2.']", f.clean, 1) 203 self.assertEqual(3, f.clean(3)) 204 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is less than or equal to 4.']", f.clean, 5) 205 206 f.min_value = 6 207 f.max_value = 8 208 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is greater than or equal to 6.']", f.clean, 3) 209 self.assertEqual(7, f.clean(7)) 210 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is less than or equal to 8.']", f.clean, 9) 211 212 f.min_value = None 213 f.max_value = None 214 self.assertEqual(1, f.clean(1)) 215 self.assertEqual(9, f.clean(9)) 216 183 217 # FloatField ################################################################## 184 218 185 219 def test_floatfield_1(self): … … class FieldsTests(TestCase): 217 251 self.assertEqual(f.max_value, 1.5) 218 252 self.assertEqual(f.min_value, 0.5) 219 253 254 def test_floatfield_validator_attributes(self): 255 f = FloatField(min_value=1.5, max_value=2.5) 256 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is greater than or equal to 1.5.']", f.clean, 1) 257 self.assertEqual(2, f.clean(2)) 258 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is less than or equal to 2.5.']", f.clean, 3) 259 260 f.min_value = 4 261 f.max_value = 5 262 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is greater than or equal to 4.']", f.clean, 3.5) 263 self.assertEqual(4.5, f.clean(4.5)) 264 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is less than or equal to 5.']", f.clean, 6.6) 265 266 f.min_value = None 267 f.max_value = None 268 self.assertEqual(0.5, f.clean(0.5)) 269 self.assertEqual(5.5, f.clean(5.5)) 270 220 271 # DecimalField ################################################################ 221 272 222 273 def test_decimalfield_1(self): … … class FieldsTests(TestCase): 297 348 self.assertEqual(f.clean('.01'), Decimal(".01")) 298 349 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure that there are no more than 0 digits before the decimal point.']", f.clean, '1.1') 299 350 351 def test_decimalfield_validator_attributes(self): 352 f = DecimalField(min_value=Decimal('1.5'), max_value=Decimal('2.5')) 353 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is greater than or equal to 1.5.']", f.clean, 1) 354 self.assertEqual(Decimal('2'), f.clean(2)) 355 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is less than or equal to 2.5.']", f.clean, 3) 356 357 f.min_value = Decimal('4') 358 f.max_value = Decimal('5') 359 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is greater than or equal to 4.']", f.clean, 3.5) 360 self.assertEqual(Decimal('4.5'), f.clean(4.5)) 361 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value is less than or equal to 5.']", f.clean, 6.6) 362 363 f.min_value = None 364 f.max_value = None 365 self.assertEqual(Decimal('0.5'), f.clean(0.5)) 366 self.assertEqual(Decimal('5.5'), f.clean(5.5)) 367 300 368 # DateField ################################################################### 301 369 302 370 def test_datefield_1(self): … … class FieldsTests(TestCase): 466 534 self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value has at most 10 characters (it has 11).']", f.clean, '12345678901') 467 535 self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid value.']", f.clean, '12345a') 468 536 537 def test_regexfield_validator_attributes(self): 538 f = RegexField('^\d+$') 539 self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid value.']", f.clean, 'abc') 540 self.assertEqual(u'1234', f.clean('1234')) 541 542 f.regex = '^[a-z]+$' 543 self.assertEqual(u'abc', f.clean('abc')) 544 self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid value.']", f.clean, '1234') 545 546 f.regex = re.compile('^[^\w]+$') 547 self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid value.']", f.clean, 'abc') 548 self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid value.']", f.clean, '1234') 549 self.assertEqual(u'--', f.clean('--')) 550 551 f.regex = None 552 self.assertEqual(u'1-b-2', f.clean('1-b-2')) 553 469 554 # EmailField ################################################################## 470 555 471 556 def test_emailfield_1(self):