BooleanField and NullBooleanField must have same parsing of True/False

values.
Also added check for unhashable types in NullBooleanField.
This commit is contained in:
Igor Tokarev 2017-09-03 18:56:09 +05:00
parent 139c8fe3d1
commit c38e23f88e
2 changed files with 40 additions and 37 deletions

View File

@ -662,17 +662,23 @@ class BooleanField(Field):
} }
def __init__(self, **kwargs): def __init__(self, **kwargs):
assert 'allow_null' not in kwargs, '`allow_null` is not a valid option. Use `NullBooleanField` instead.' kwargs = self._validate_and_update_kwargs(kwargs)
super(BooleanField, self).__init__(**kwargs) super(BooleanField, self).__init__(**kwargs)
def to_internal_value(self, data): def _validate_and_update_kwargs(self, kwargs):
try: assert 'allow_null' not in kwargs, '`allow_null` is not a valid option. Use `NullBooleanField` instead.'
return kwargs
def _to_internal(self, data):
if data in self.TRUE_VALUES: if data in self.TRUE_VALUES:
return True return True
elif data in self.FALSE_VALUES: elif data in self.FALSE_VALUES:
return False return False
except TypeError: # Input is an unhashable type self.fail('invalid', input=data)
pass
def to_internal_value(self, data):
if isinstance(data, collections.Hashable):
return self._to_internal(data)
self.fail('invalid', input=data) self.fail('invalid', input=data)
def to_representation(self, value): def to_representation(self, value):
@ -683,37 +689,30 @@ class BooleanField(Field):
return bool(value) return bool(value)
class NullBooleanField(Field): class NullBooleanField(BooleanField):
default_error_messages = {
'invalid': _('"{input}" is not a valid boolean.')
}
initial = None initial = None
TRUE_VALUES = {'t', 'T', 'true', 'True', 'TRUE', '1', 1, True} default_empty_html = empty
FALSE_VALUES = {'f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False} NULL_VALUES = {
NULL_VALUES = {'n', 'N', 'null', 'Null', 'NULL', '', None} 'n', 'N',
'null', 'Null', 'NULL',
'',
None
}
def __init__(self, **kwargs): def _validate_and_update_kwargs(self, kwargs):
assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.' assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.'
kwargs['allow_null'] = True kwargs['allow_null'] = True
super(NullBooleanField, self).__init__(**kwargs) return kwargs
def to_internal_value(self, data): def _to_internal(self, data):
if data in self.TRUE_VALUES: if data in self.NULL_VALUES:
return True
elif data in self.FALSE_VALUES:
return False
elif data in self.NULL_VALUES:
return None return None
self.fail('invalid', input=data) return super(NullBooleanField, self)._to_internal(data)
def to_representation(self, value): def to_representation(self, value):
if value in self.NULL_VALUES: if value in self.NULL_VALUES:
return None return None
if value in self.TRUE_VALUES: return super(NullBooleanField, self).to_representation(value)
return True
elif value in self.FALSE_VALUES:
return False
return bool(value)
# String types... # String types...

View File

@ -558,6 +558,7 @@ class TestBooleanField(FieldValues):
valid_inputs = { valid_inputs = {
'true': True, 'true': True,
'false': False, 'false': False,
'on': True,
'1': True, '1': True,
'0': False, '0': False,
1: True, 1: True,
@ -572,6 +573,7 @@ class TestBooleanField(FieldValues):
outputs = { outputs = {
'true': True, 'true': True,
'false': False, 'false': False,
'on': True,
'1': True, '1': True,
'0': False, '0': False,
1: True, 1: True,
@ -602,6 +604,7 @@ class TestNullBooleanField(FieldValues):
valid_inputs = { valid_inputs = {
'true': True, 'true': True,
'false': False, 'false': False,
'on': True,
'null': None, 'null': None,
True: True, True: True,
False: False, False: False,
@ -613,6 +616,7 @@ class TestNullBooleanField(FieldValues):
outputs = { outputs = {
'true': True, 'true': True,
'false': False, 'false': False,
'on': True,
'null': None, 'null': None,
True: True, True: True,
False: False, False: False,