Changeset 8771
- Timestamp:
- 08/31/08 15:10:50 (3 months ago)
- Files:
-
- django/trunk/django/forms/fields.py (modified) (3 diffs)
- django/trunk/docs/ref/forms/fields.txt (modified) (1 diff)
- django/trunk/tests/regressiontests/forms/fields.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/forms/fields.py
r8661 r8771 24 24 from sets import Set as set 25 25 26 import django.core.exceptions 26 27 from django.utils.translation import ugettext_lazy as _ 27 28 from django.utils.encoding import smart_unicode, smart_str … … 40 41 'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', 41 42 'SplitDateTimeField', 'IPAddressField', 'FilePathField', 'SlugField', 43 'TypedChoiceField' 42 44 ) 43 45 … … 657 659 return True 658 660 return False 661 662 class TypedChoiceField(ChoiceField): 663 def __init__(self, *args, **kwargs): 664 self.coerce = kwargs.pop('coerce', lambda val: val) 665 self.empty_value = kwargs.pop('empty_value', '') 666 super(TypedChoiceField, self).__init__(*args, **kwargs) 667 668 def clean(self, value): 669 """ 670 Validate that the value is in self.choices and can be coerced to the 671 right type. 672 """ 673 value = super(TypedChoiceField, self).clean(value) 674 if value == self.empty_value or value in EMPTY_VALUES: 675 return self.empty_value 676 677 # Hack alert: This field is purpose-made to use with Field.to_python as 678 # a coercion function so that ModelForms with choices work. However, 679 # Django's Field.to_python raises django.core.exceptions.ValidationError, 680 # which is a *different* exception than 681 # django.forms.utils.ValidationError. So unfortunatly we need to catch 682 # both. 683 try: 684 value = self.coerce(value) 685 except (ValueError, TypeError, django.core.exceptions.ValidationError): 686 raise ValidationError(self.error_messages['invalid_choice'] % {'value': value}) 687 return value 659 688 660 689 class MultipleChoiceField(ChoiceField): django/trunk/docs/ref/forms/fields.txt
r8616 r8771 363 363 An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this 364 364 field. 365 366 ``TypedChoiceField`` 367 ~~~~~~~~~~~~~~~~~~~~ 368 369 .. class:: TypedChoiceField(**kwargs) 370 371 Just like a :class:`ChoiceField`, except :class:`TypedChoiceField` takes an 372 extra ``coerce`` argument. 373 374 * Default widget: ``Select`` 375 * Empty value: Whatever you've given as ``empty_value`` 376 * Normalizes to: the value returned by the ``coerce`` argument. 377 * Validates that the given value exists in the list of choices. 378 * Error message keys: ``required``, ``invalid_choice`` 379 380 Takes extra arguments: 381 382 .. attribute:: TypedChoiceField.coerce 383 384 A function that takes one argument and returns a coerced value. Examples 385 include the built-in ``int``, ``float``, ``bool`` and other types. Defaults 386 to an identity function. 387 388 .. attribute:: TypedChoiceField.empty_value 389 390 The value to use to represent "empty." Defaults to the empty string; 391 ``None`` is another common choice here. 365 392 366 393 ``DateField`` django/trunk/tests/regressiontests/forms/fields.py
r8661 r8771 1078 1078 ValidationError: [u'Select a valid choice. 6 is not one of the available choices.'] 1079 1079 1080 # TypedChoiceField ############################################################ 1081 1082 # TypedChoiceField is just like ChoiceField, except that coerced types will 1083 # be returned: 1084 >>> f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int) 1085 >>> f.clean('1') 1086 1 1087 >>> f.clean('2') 1088 Traceback (most recent call last): 1089 ... 1090 ValidationError: [u'Select a valid choice. 2 is not one of the available choices.'] 1091 1092 # Different coercion, same validation. 1093 >>> f.coerce = float 1094 >>> f.clean('1') 1095 1.0 1096 1097 1098 # This can also cause weirdness: be careful (bool(-1) == True, remember) 1099 >>> f.coerce = bool 1100 >>> f.clean('-1') 1101 True 1102 1103 # Even more weirdness: if you have a valid choice but your coercion function 1104 # can't coerce, you'll still get a validation error. Don't do this! 1105 >>> f = TypedChoiceField(choices=[('A', 'A'), ('B', 'B')], coerce=int) 1106 >>> f.clean('B') 1107 Traceback (most recent call last): 1108 ... 1109 ValidationError: [u'Select a valid choice. B is not one of the available choices.'] 1110 1111 # Required fields require values 1112 >>> f.clean('') 1113 Traceback (most recent call last): 1114 ... 1115 ValidationError: [u'This field is required.'] 1116 1117 # Non-required fields aren't required 1118 >>> f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False) 1119 >>> f.clean('') 1120 '' 1121 1122 # If you want cleaning an empty value to return a different type, tell the field 1123 >>> f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False, empty_value=None) 1124 >>> print f.clean('') 1125 None 1126 1080 1127 # NullBooleanField ############################################################ 1081 1128
