Skip to content

Commit ad6533e

Browse files
committed
Merge pull request #2294 from tomchristie/fix-empty-html-values-with-default
Fix empty HTML values when a default is provided.
2 parents ffc099a + 3fff5cb commit ad6533e

File tree

3 files changed

+27
-0
lines changed

3 files changed

+27
-0
lines changed

docs/api-guide/fields.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ Two options are currently used in HTML form generation, `'input_type'` and `'bas
112112

113113
A boolean representation.
114114

115+
When using HTML encoded form input be aware that omitting a value will always be treated as setting a field to `False`, even if it has a `default=True` option specified. This is because HTML checkbox inputs represent the unchecked state by omitting the value, so REST framework treats omission as if it is an empty checkbox input.
116+
115117
Corresponds to `django.db.models.fields.BooleanField`.
116118

117119
**Signature:** `BooleanField()`

rest_framework/fields.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,13 @@ def __init__(self, read_only=False, write_only=False,
185185
self.allow_null = allow_null
186186

187187
if allow_null and self.default_empty_html is empty:
188+
# HTML input cannot represent `None` values, so we need to
189+
# forcibly coerce empty HTML values to `None` if `allow_null=True`.
188190
self.default_empty_html = None
189191

192+
if default is not empty:
193+
self.default_empty_html = default
194+
190195
if validators is not None:
191196
self.validators = validators[:]
192197

tests/test_fields.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,26 @@ class MockHTMLDict(dict):
215215
assert serializer.validated_data == {'archived': False}
216216

217217

218+
class TestCharHTMLInput:
219+
def setup(self):
220+
class TestSerializer(serializers.Serializer):
221+
message = serializers.CharField(default='happy')
222+
self.Serializer = TestSerializer
223+
224+
def test_empty_html_checkbox(self):
225+
"""
226+
HTML checkboxes do not send any value, but should be treated
227+
as `False` by BooleanField.
228+
"""
229+
# This class mocks up a dictionary like object, that behaves
230+
# as if it was returned for multipart or urlencoded data.
231+
class MockHTMLDict(dict):
232+
getlist = None
233+
serializer = self.Serializer(data=MockHTMLDict())
234+
assert serializer.is_valid()
235+
assert serializer.validated_data == {'message': 'happy'}
236+
237+
218238
class TestCreateOnlyDefault:
219239
def setup(self):
220240
default = serializers.CreateOnlyDefault('2001-01-01')

0 commit comments

Comments
 (0)