diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 41d6105ca..982aa0769 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -424,7 +424,7 @@ class Field(object): if getattr(self.root, 'partial', False): return empty return self.default_empty_html - ret = dictionary[self.field_name] + ret = dictionary.getlist(self.field_name) if ret == '' and self.allow_null: # If the field is blank, and null is a valid value then # determine if we should use null instead. diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index e27610178..6e92cb5ec 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -11,7 +11,7 @@ python primitives. response content is handled by parsers and renderers. """ from __future__ import unicode_literals - +import re import copy import inspect import traceback @@ -367,10 +367,15 @@ class Serializer(BaseSerializer): @cached_property def _writable_fields(self): - return [ - field for field in self.fields.values() - if (not field.read_only) or (field.default is not empty) - ] + ret = [] + for field in self.fields.values(): + if re.compile("\_set$").findall(field.source): + for field in field.child._writable_fields: + ret.append(field) + continue + if (not field.read_only) or (field.default is not empty): + ret.append(field) + return ret @cached_property def _readable_fields(self): @@ -454,26 +459,29 @@ class Serializer(BaseSerializer): ret = OrderedDict() errors = OrderedDict() fields = self._writable_fields - for field in fields: validate_method = getattr(self, 'validate_' + field.field_name, None) primitive_value = field.get_value(data) - try: - validated_value = field.run_validation(primitive_value) - if validate_method is not None: - validated_value = validate_method(validated_value) - except ValidationError as exc: - errors[field.field_name] = exc.detail - except DjangoValidationError as exc: - errors[field.field_name] = get_error_detail(exc) - except SkipField: - pass + validated_list = [] + for inner_data in primitive_value: + try: + validated_value = field.run_validation(inner_data) + validated_list.append(validated_value) + if validate_method is not None: + validated_list.append(validate_method(validated_value)) + except ValidationError as exc: + errors[field.field_name] = exc.detail + except DjangoValidationError as exc: + errors[field.field_name] = get_error_detail(exc) + except SkipField: + pass else: - set_value(ret, field.source_attrs, validated_value) - + if len(validated_list) > 1: + set_value(ret, field.source_attrs, validated_list) + else: + set_value(ret, field.source_attrs, validated_list[0]) if errors: raise ValidationError(errors) - return ret def to_representation(self, instance):