diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 5730ca571..d2079d5d6 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -688,8 +688,22 @@ class NullBooleanField(Field): 'invalid': _('"{input}" is not a valid boolean.') } initial = None - TRUE_VALUES = {'t', 'T', 'true', 'True', 'TRUE', '1', 1, True} - FALSE_VALUES = {'f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False} + TRUE_VALUES = { + 't', 'T', + 'y', 'Y', 'yes', 'YES', + 'true', 'True', 'TRUE', + 'on', 'On', 'ON', + '1', 1, + True + } + FALSE_VALUES = { + 'f', 'F', + 'n', 'N', 'no', 'NO', + 'false', 'False', 'FALSE', + 'off', 'Off', 'OFF', + '0', 0, 0.0, + False + } NULL_VALUES = {'n', 'N', 'null', 'Null', 'NULL', '', None} def __init__(self, **kwargs): @@ -698,12 +712,15 @@ class NullBooleanField(Field): super(NullBooleanField, self).__init__(**kwargs) def to_internal_value(self, data): - if data in self.TRUE_VALUES: - return True - elif data in self.FALSE_VALUES: - return False - elif data in self.NULL_VALUES: - return None + try: + if data in self.TRUE_VALUES: + return True + elif data in self.FALSE_VALUES: + return False + elif data in self.NULL_VALUES: + return None + except TypeError: # Input is an unhashable type + pass self.fail('invalid', input=data) def to_representation(self, value): diff --git a/tests/test_fields.py b/tests/test_fields.py index d6b233227..c3d2bf57d 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -587,7 +587,7 @@ class TestBooleanField(FieldValues): [], {}, ) - field = serializers.BooleanField() + field = self.field for input_value in inputs: with pytest.raises(serializers.ValidationError) as exc_info: field.run_validation(input_value) @@ -595,7 +595,7 @@ class TestBooleanField(FieldValues): assert exc_info.value.detail == expected -class TestNullBooleanField(FieldValues): +class TestNullBooleanField(TestBooleanField): """ Valid and invalid values for `BooleanField`. """