diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 0b214b872..7d3ae6a6d 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1461,7 +1461,7 @@ class ListField(Field): """ if html.is_html_input(data): data = html.parse_html_list(data) - if isinstance(data, type('')) or not hasattr(data, '__iter__'): + if isinstance(data, type('')) or isinstance(data, collections.Mapping) or not hasattr(data, '__iter__'): self.fail('not_a_list', input_type=type(data).__name__) if not self.allow_empty and len(data) == 0: self.fail('empty') diff --git a/tests/test_fields.py b/tests/test_fields.py index 104337627..8d3bef106 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -1437,7 +1437,8 @@ class TestListField(FieldValues): ] invalid_inputs = [ ('not a list', ['Expected a list of items but got type "str".']), - ([1, 2, 'error'], ['A valid integer is required.']) + ([1, 2, 'error'], ['A valid integer is required.']), + ({'one': 'two'}, ['Expected a list of items but got type "dict".']) ] outputs = [ ([1, 2, 3], [1, 2, 3]), @@ -1454,6 +1455,14 @@ class TestListField(FieldValues): "Remove `source=` from the field declaration." ) + def test_collection_types_are_invalid_input(self): + field = serializers.ListField(child=serializers.CharField()) + input_value = ({'one': 'two'}) + + with pytest.raises(serializers.ValidationError) as exc_info: + field.to_internal_value(input_value) + assert exc_info.value.detail == ['Expected a list of items but got type "dict".'] + class TestEmptyListField(FieldValues): """