Add hooks to customize error output

This commit is contained in:
Loïs BURG 2013-11-19 14:22:09 +01:00
parent fb3fcf0710
commit 301ab5f88e

View File

@ -231,6 +231,50 @@ class BaseSerializer(WritableField):
return ret
#####
# Methods to insert an error in the errors dict.
def get_non_field_error_key(self):
"""
Return the key under which to store non field related errors.
"""
return "non_field_errors"
def format_full_clean_errors(self, errors, instance, full_clean_error):
"""
Handling formatting errors generated by Django's full_clean method.
"""
return full_clean_error.message_dict
def format_non_field_error(self, errors, data, non_field_error):
"""
Handles formatting non field related errors.
"""
current_list = errors.setdefault(self.get_non_field_error_key(), [])
if isinstance(non_field_error, list):
current_list.extend(non_field_error)
else:
current_list.append(non_field_error)
return errors
def format_field_error(self, errors, data, field_name, field_error):
"""
Handles formatting field specific errors.
"""
current_list = errors.setdefault(field_name, [])
if isinstance(field_error, list):
current_list.extend(field_error)
else:
current_list.append(field_error)
return errors
def format_many_error(self, errors, data, data_errors):
"""
Handles formatting bulk operations errors.
"""
errors.append(data_errors)
return errors
#####
# Methods to convert or revert from objects <--> primitive representations.
@ -248,7 +292,7 @@ class BaseSerializer(WritableField):
reverted_data = {}
if data is not None and not isinstance(data, dict):
self._errors['non_field_errors'] = ['Invalid data']
self._errors = self.format_non_field_error(self._errors, None, 'Invalid data')
return None
for field_name, field in self.fields.items():
@ -256,11 +300,11 @@ class BaseSerializer(WritableField):
try:
field.field_from_native(data, files, field_name, reverted_data)
except ValidationError as err:
self._errors[field_name] = list(err.messages)
self._errors = self.format_field_error(self._errors, data, field_name, list(err.messages))
return reverted_data
def perform_validation(self, attrs):
def perform_validation(self, attrs, data):
"""
Run `validate_<fieldname>()` and `validate()` methods on the serializer
"""
@ -276,7 +320,7 @@ class BaseSerializer(WritableField):
if validate_method:
attrs = validate_method(attrs, source)
except ValidationError as err:
self._errors[field_name] = self._errors.get(field_name, []) + list(err.messages)
self._errors = self.format_field_error(self._errors, data, field_name, list(err.messages))
# If there are already errors, we don't run .validate() because
# field-validation failed and thus `attrs` may not be complete.
@ -287,9 +331,9 @@ class BaseSerializer(WritableField):
except ValidationError as err:
if hasattr(err, 'message_dict'):
for field_name, error_messages in err.message_dict.items():
self._errors[field_name] = self._errors.get(field_name, []) + list(error_messages)
self._errors = self.format_field_error(self._errors, data, field_name, list(error_messages))
elif hasattr(err, 'messages'):
self._errors['non_field_errors'] = err.messages
self._errors = self.format_non_field_error(self._errors, data, err.messages)
return attrs
@ -340,9 +384,9 @@ class BaseSerializer(WritableField):
if data is not None or files is not None:
attrs = self.restore_fields(data, files)
if attrs is not None:
attrs = self.perform_validation(attrs)
attrs = self.perform_validation(attrs, data)
else:
self._errors['non_field_errors'] = ['No input provided']
self._errors = self.format_non_field_error(self._errors, None, 'No input provided')
if not self._errors:
return self.restore_object(attrs, instance=getattr(self, 'object', None))
@ -491,18 +535,18 @@ class BaseSerializer(WritableField):
self.object = identity_to_objects.pop(identity, None)
if self.object is None and not self.allow_add_remove:
ret.append(None)
errors.append({'non_field_errors': ['Cannot create a new item, only existing items may be updated.']})
errors.append(self.format_non_field_error({}, item, 'Cannot create a new item, only existing items may be updated.'))
continue
ret.append(self.from_native(item, None))
errors.append(self._errors)
self.format_many_error(errors, item, self._errors)
if update and self.allow_add_remove:
ret._deleted = identity_to_objects.values()
self._errors = any(errors) and errors or []
else:
self._errors = {'non_field_errors': ['Expected a list of items.']}
self._errors = self.format_non_field_error({}, None, 'Expected a list of items.')
else:
ret = self.from_native(data, files)
@ -857,7 +901,7 @@ class ModelSerializer(Serializer):
try:
instance.full_clean(exclude=self.get_validation_exclusions())
except ValidationError as err:
self._errors = err.message_dict
self._errors = self.format_full_clean_errors(self._errors, instance, err)
return None
return instance