Fix BooleanField's allow_null behavior (#8614)

* Fix BooleanField's allow_null behavior

* Update rest_framework.fields

- Use .get with default value for 'allow_null' kwarg in BooleanField's
  init
This commit is contained in:
Rodrigo 2022-12-06 06:04:50 -03:00 committed by GitHub
parent ee15731cbc
commit 1fbe16a8d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 2 deletions

View File

@ -690,6 +690,12 @@ class BooleanField(Field):
} }
NULL_VALUES = {'null', 'Null', 'NULL', '', None} NULL_VALUES = {'null', 'Null', 'NULL', '', None}
def __init__(self, **kwargs):
if kwargs.get('allow_null', False):
self.default_empty_html = None
self.initial = None
super().__init__(**kwargs)
def to_internal_value(self, data): def to_internal_value(self, data):
with contextlib.suppress(TypeError): with contextlib.suppress(TypeError):
if data in self.TRUE_VALUES: if data in self.TRUE_VALUES:

View File

@ -371,7 +371,7 @@ class TestBooleanHTMLInput:
def test_empty_html_checkbox(self): def test_empty_html_checkbox(self):
""" """
HTML checkboxes do not send any value, but should be treated HTML checkboxes do not send any value, but should be treated
as `False` by BooleanField. as `False` by BooleanField if allow_null=False.
""" """
class TestSerializer(serializers.Serializer): class TestSerializer(serializers.Serializer):
archived = serializers.BooleanField() archived = serializers.BooleanField()
@ -383,7 +383,8 @@ class TestBooleanHTMLInput:
def test_empty_html_checkbox_not_required(self): def test_empty_html_checkbox_not_required(self):
""" """
HTML checkboxes do not send any value, but should be treated HTML checkboxes do not send any value, but should be treated
as `False` by BooleanField, even if the field is required=False. as `False` by BooleanField when the field is required=False
and allow_null=False.
""" """
class TestSerializer(serializers.Serializer): class TestSerializer(serializers.Serializer):
archived = serializers.BooleanField(required=False) archived = serializers.BooleanField(required=False)
@ -392,6 +393,34 @@ class TestBooleanHTMLInput:
assert serializer.is_valid() assert serializer.is_valid()
assert serializer.validated_data == {'archived': False} assert serializer.validated_data == {'archived': False}
def test_empty_html_checkbox_allow_null(self):
"""
HTML checkboxes do not send any value and should be treated
as `None` by BooleanField if allow_null is True.
"""
class TestSerializer(serializers.Serializer):
archived = serializers.BooleanField(allow_null=True)
serializer = TestSerializer(data=QueryDict(''))
assert serializer.is_valid()
assert serializer.validated_data == {'archived': None}
def test_empty_html_checkbox_allow_null_with_default(self):
"""
BooleanField should respect default if set and still allow
setting null values.
"""
class TestSerializer(serializers.Serializer):
archived = serializers.BooleanField(allow_null=True, default=True)
serializer = TestSerializer(data=QueryDict(''))
assert serializer.is_valid()
assert serializer.validated_data == {'archived': True}
serializer = TestSerializer(data=QueryDict('archived='))
assert serializer.is_valid()
assert serializer.validated_data == {'archived': None}
class TestHTMLInput: class TestHTMLInput:
def test_empty_html_charfield_with_default(self): def test_empty_html_charfield_with_default(self):