diff --git a/django/forms/fields.py b/django/forms/fields.py index bc3770150a..4a07dc3542 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -778,14 +778,15 @@ class ChoiceField(Field): def valid_value(self, value): "Check to see if the provided value is a valid choice" + text_value = force_text(value) for k, v in self.choices: if isinstance(v, (list, tuple)): # This is an optgroup, so look inside the group for options for k2, v2 in v: - if value == smart_text(k2): + if value == k2 or text_value == force_text(k2): return True else: - if value == smart_text(k): + if value == k or text_value == force_text(k): return True return False @@ -801,7 +802,6 @@ class TypedChoiceField(ChoiceField): right type. """ value = super(TypedChoiceField, self).to_python(value) - super(TypedChoiceField, self).validate(value) if value == self.empty_value or value in self.empty_values: return self.empty_value try: @@ -810,9 +810,6 @@ class TypedChoiceField(ChoiceField): raise ValidationError(self.error_messages['invalid_choice'] % {'value': value}) return value - def validate(self, value): - pass - class MultipleChoiceField(ChoiceField): hidden_widget = MultipleHiddenInput @@ -864,7 +861,6 @@ class TypedMultipleChoiceField(MultipleChoiceField): right type. """ value = super(TypedMultipleChoiceField, self).to_python(value) - super(TypedMultipleChoiceField, self).validate(value) if value == self.empty_value or value in self.empty_values: return self.empty_value new_value = [] @@ -876,7 +872,11 @@ class TypedMultipleChoiceField(MultipleChoiceField): return new_value def validate(self, value): - pass + if value != self.empty_value: + super(TypedMultipleChoiceField, self).validate(value) + elif self.required: + raise ValidationError(self.error_messages['required']) + class ComboField(Field): """ diff --git a/tests/forms_tests/tests/fields.py b/tests/forms_tests/tests/fields.py index 3d3206ef85..95e14c4434 100644 --- a/tests/forms_tests/tests/fields.py +++ b/tests/forms_tests/tests/fields.py @@ -911,6 +911,11 @@ class FieldsTests(SimpleTestCase): f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False, empty_value=None) self.assertEqual(None, f.clean('')) + def test_typedchoicefield_has_changed(self): + # has_changed should not trigger required validation + f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=True) + self.assertFalse(f._has_changed(None, '')) + # NullBooleanField ############################################################ def test_nullbooleanfield_1(self): @@ -1060,6 +1065,11 @@ class FieldsTests(SimpleTestCase): f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False, empty_value=None) self.assertEqual(None, f.clean([])) + def test_typedmultiplechoicefield_has_changed(self): + # has_changed should not trigger required validation + f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=True) + self.assertFalse(f._has_changed(None, '')) + # ComboField ################################################################## def test_combofield_1(self): diff --git a/tests/forms_tests/tests/regressions.py b/tests/forms_tests/tests/regressions.py index 4249b8afb7..ba741bc16b 100644 --- a/tests/forms_tests/tests/regressions.py +++ b/tests/forms_tests/tests/regressions.py @@ -61,10 +61,10 @@ class FormsRegressionsTestCase(TestCase): UNITS = ((b'\xd0\xbc\xd0\xb5\xd1\x81.', b'\xd0\xbc\xd0\xb5\xd1\x81.'), (b'\xd1\x88\xd1\x82.', b'\xd1\x88\xd1\x82.')) f = ChoiceField(choices=UNITS) - self.assertEqual(f.clean('\u0448\u0442.'), '\u0448\u0442.') with warnings.catch_warnings(): # Ignore UnicodeWarning warnings.simplefilter("ignore") + self.assertEqual(f.clean('\u0448\u0442.'), '\u0448\u0442.') self.assertEqual(f.clean(b'\xd1\x88\xd1\x82.'), '\u0448\u0442.') # Translated error messages used to be buggy.