From 7af79a02231197cd07cadb1b4a3b66efbfe4d039 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Mon, 29 Nov 2021 20:27:52 -0300 Subject: [PATCH 1/2] Fix BooleanField's allow_null behavior --- rest_framework/fields.py | 6 ++++++ tests/test_fields.py | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 5cafed5556..949215003e 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -720,6 +720,12 @@ class BooleanField(Field): } NULL_VALUES = {'null', 'Null', 'NULL', '', None} + def __init__(self, **kwargs): + if 'allow_null' in kwargs: + self.default_empty_html = None + self.initial = None + super().__init__(**kwargs) + def to_internal_value(self, data): try: if data in self.TRUE_VALUES: diff --git a/tests/test_fields.py b/tests/test_fields.py index 7a5304a82a..f58bf599e5 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -363,7 +363,7 @@ class TestBooleanHTMLInput: def test_empty_html_checkbox(self): """ 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): archived = serializers.BooleanField() @@ -375,7 +375,8 @@ class TestSerializer(serializers.Serializer): def test_empty_html_checkbox_not_required(self): """ 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): archived = serializers.BooleanField(required=False) @@ -384,6 +385,34 @@ class TestSerializer(serializers.Serializer): assert serializer.is_valid() 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: def test_empty_html_charfield_with_default(self): From c29bb0937942b98017cec1a25ec6d10cc6d881d5 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 19 Oct 2022 12:37:04 -0300 Subject: [PATCH 2/2] Update rest_framework.fields - Use .get with default value for 'allow_null' kwarg in BooleanField's init --- rest_framework/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 9832701e29..3a5df4abea 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -691,7 +691,7 @@ class BooleanField(Field): NULL_VALUES = {'null', 'Null', 'NULL', '', None} def __init__(self, **kwargs): - if 'allow_null' in kwargs: + if kwargs.get('allow_null', False): self.default_empty_html = None self.initial = None super().__init__(**kwargs)