Skip to content

Commit 7af79a0

Browse files
committed
Fix BooleanField's allow_null behavior
1 parent 580bf45 commit 7af79a0

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

rest_framework/fields.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,12 @@ class BooleanField(Field):
720720
}
721721
NULL_VALUES = {'null', 'Null', 'NULL', '', None}
722722

723+
def __init__(self, **kwargs):
724+
if 'allow_null' in kwargs:
725+
self.default_empty_html = None
726+
self.initial = None
727+
super().__init__(**kwargs)
728+
723729
def to_internal_value(self, data):
724730
try:
725731
if data in self.TRUE_VALUES:

tests/test_fields.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ class TestBooleanHTMLInput:
363363
def test_empty_html_checkbox(self):
364364
"""
365365
HTML checkboxes do not send any value, but should be treated
366-
as `False` by BooleanField.
366+
as `False` by BooleanField if allow_null=False.
367367
"""
368368
class TestSerializer(serializers.Serializer):
369369
archived = serializers.BooleanField()
@@ -375,7 +375,8 @@ class TestSerializer(serializers.Serializer):
375375
def test_empty_html_checkbox_not_required(self):
376376
"""
377377
HTML checkboxes do not send any value, but should be treated
378-
as `False` by BooleanField, even if the field is required=False.
378+
as `False` by BooleanField when the field is required=False
379+
and allow_null=False.
379380
"""
380381
class TestSerializer(serializers.Serializer):
381382
archived = serializers.BooleanField(required=False)
@@ -384,6 +385,34 @@ class TestSerializer(serializers.Serializer):
384385
assert serializer.is_valid()
385386
assert serializer.validated_data == {'archived': False}
386387

388+
def test_empty_html_checkbox_allow_null(self):
389+
"""
390+
HTML checkboxes do not send any value and should be treated
391+
as `None` by BooleanField if allow_null is True.
392+
"""
393+
class TestSerializer(serializers.Serializer):
394+
archived = serializers.BooleanField(allow_null=True)
395+
396+
serializer = TestSerializer(data=QueryDict(''))
397+
assert serializer.is_valid()
398+
assert serializer.validated_data == {'archived': None}
399+
400+
def test_empty_html_checkbox_allow_null_with_default(self):
401+
"""
402+
BooleanField should respect default if set and still allow
403+
setting null values.
404+
"""
405+
class TestSerializer(serializers.Serializer):
406+
archived = serializers.BooleanField(allow_null=True, default=True)
407+
408+
serializer = TestSerializer(data=QueryDict(''))
409+
assert serializer.is_valid()
410+
assert serializer.validated_data == {'archived': True}
411+
412+
serializer = TestSerializer(data=QueryDict('archived='))
413+
assert serializer.is_valid()
414+
assert serializer.validated_data == {'archived': None}
415+
387416

388417
class TestHTMLInput:
389418
def test_empty_html_charfield_with_default(self):

0 commit comments

Comments
 (0)