From 55f6427ef4dbbc8a290763582567f61cb30754e2 Mon Sep 17 00:00:00 2001 From: Andrew Backer Date: Wed, 7 Feb 2018 12:45:33 +0800 Subject: [PATCH] Fix support for ListField default values in HTML mode The ListField handles html forms data differently than json data. This section would always return a value (an empty list) for a list field, even when that field name was not posted at all. This change checks for the field being present and returns `empty` if it is not; this lets the standard default-value and required field handling take over. --- rest_framework/fields.py | 2 ++ tests/test_fields.py | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index a336528e8..0684abfc2 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1609,6 +1609,8 @@ class ListField(Field): # We override the default field access in order to support # lists in HTML forms. if html.is_html_input(dictionary): + if self.field_name not in dictionary: + return empty val = dictionary.getlist(self.field_name, []) if len(val) > 0: # Support QueryDict lists in HTML input. diff --git a/tests/test_fields.py b/tests/test_fields.py index 35593a283..03613bbf9 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -459,6 +459,31 @@ class TestHTMLInput: assert serializer.is_valid() assert serializer.validated_data == {'scores': [1]} + def test_querydict_list_input_no_values_uses_default(self): + """ + When there are no values passed in, and default is set + The field should return the default value + """ + class TestSerializer(serializers.Serializer): + a = serializers.IntegerField(required=True) + scores = serializers.ListField(default=lambda: [1, 3]) + + serializer = TestSerializer(data=QueryDict('a=1&')) + assert serializer.is_valid() + assert serializer.validated_data == {'a': 1, 'scores': [1, 3]} + + def test_querydict_list_input_no_values_no_default_and_not_required(self): + """ + When there are no keys passed, there is no default, and required=False + The field should be skipped + """ + class TestSerializer(serializers.Serializer): + scores = serializers.ListField(required=False) + + serializer = TestSerializer(data=QueryDict('')) + assert serializer.is_valid() + assert serializer.validated_data == {} + class TestCreateOnlyDefault: def setup(self):