Kaydet (Commit) f34cfec0 authored tarafından Loic Bistuer's avatar Loic Bistuer Kaydeden (comit) Tim Graham

Refactored ValidationError to allow persisting error params and error codes as…

Refactored ValidationError to allow persisting error params and error codes as the exception bubbles up
üst efe6e160
......@@ -3,6 +3,9 @@ Global Django exception and warning classes.
"""
import logging
from functools import reduce
import operator
from django.utils.encoding import force_text
class DjangoRuntimeWarning(RuntimeWarning):
......@@ -74,46 +77,67 @@ NON_FIELD_ERRORS = '__all__'
class ValidationError(Exception):
"""An error while validating data."""
def __init__(self, message, code=None, params=None):
import operator
from django.utils.encoding import force_text
"""
ValidationError can be passed any object that can be printed (usually
a string), a list of objects or a dictionary.
"""
if isinstance(message, dict):
self.message_dict = message
# Reduce each list of messages into a single list.
message = reduce(operator.add, message.values())
if isinstance(message, list):
self.messages = [force_text(msg) for msg in message]
self.error_dict = message
elif isinstance(message, list):
self.error_list = message
else:
self.code = code
self.params = params
message = force_text(message)
self.messages = [message]
self.message = message
self.error_list = [self]
@property
def message_dict(self):
message_dict = {}
for field, messages in self.error_dict.items():
message_dict[field] = []
for message in messages:
if isinstance(message, ValidationError):
message_dict[field].extend(message.messages)
else:
message_dict[field].append(force_text(message))
return message_dict
@property
def messages(self):
if hasattr(self, 'error_dict'):
message_list = reduce(operator.add, self.error_dict.values())
else:
message_list = self.error_list
messages = []
for message in message_list:
if isinstance(message, ValidationError):
params = message.params
message = message.message
if params:
message %= params
message = force_text(message)
else:
message = force_text(message)
messages.append(message)
return messages
def __str__(self):
# This is needed because, without a __str__(), printing an exception
# instance would result in this:
# AttributeError: ValidationError instance has no attribute 'args'
# See http://www.python.org/doc/current/tut/node10.html#handling
if hasattr(self, 'message_dict'):
if hasattr(self, 'error_dict'):
return repr(self.message_dict)
return repr(self.messages)
def __repr__(self):
if hasattr(self, 'message_dict'):
return 'ValidationError(%s)' % repr(self.message_dict)
return 'ValidationError(%s)' % repr(self.messages)
return 'ValidationError(%s)' % self
def update_error_dict(self, error_dict):
if hasattr(self, 'message_dict'):
if hasattr(self, 'error_dict'):
if error_dict:
for k, v in self.message_dict.items():
for k, v in self.error_dict.items():
error_dict.setdefault(k, []).extend(v)
else:
error_dict = self.message_dict
error_dict = self.error_dict
else:
error_dict[NON_FIELD_ERRORS] = self.messages
error_dict[NON_FIELD_ERRORS] = self.error_list
return error_dict
......@@ -910,7 +910,7 @@ class Model(six.with_metaclass(ModelBase)):
'field_label': six.text_type(field_labels)
}
def full_clean(self, exclude=None):
def full_clean(self, exclude=None, validate_unique=True):
"""
Calls clean_fields, clean, and validate_unique, on the model,
and raises a ``ValidationError`` for any errors that occurred.
......@@ -932,13 +932,14 @@ class Model(six.with_metaclass(ModelBase)):
errors = e.update_error_dict(errors)
# Run unique checks, but only for fields that passed validation.
for name in errors.keys():
if name != NON_FIELD_ERRORS and name not in exclude:
exclude.append(name)
try:
self.validate_unique(exclude=exclude)
except ValidationError as e:
errors = e.update_error_dict(errors)
if validate_unique:
for name in errors.keys():
if name != NON_FIELD_ERRORS and name not in exclude:
exclude.append(name)
try:
self.validate_unique(exclude=exclude)
except ValidationError as e:
errors = e.update_error_dict(errors)
if errors:
raise ValidationError(errors)
......@@ -963,7 +964,7 @@ class Model(six.with_metaclass(ModelBase)):
try:
setattr(self, f.attname, f.clean(raw_value, self))
except ValidationError as e:
errors[f.name] = e.messages
errors[f.name] = e.error_list
if errors:
raise ValidationError(errors)
......
......@@ -208,12 +208,9 @@ class Field(object):
v(value)
except exceptions.ValidationError as e:
if hasattr(e, 'code') and e.code in self.error_messages:
message = self.error_messages[e.code]
if e.params:
message = message % e.params
errors.append(message)
else:
errors.extend(e.messages)
e.message = self.error_messages[e.code]
errors.extend(e.error_list)
if errors:
raise exceptions.ValidationError(errors)
......
......@@ -136,12 +136,8 @@ class Field(object):
v(value)
except ValidationError as e:
if hasattr(e, 'code') and e.code in self.error_messages:
message = self.error_messages[e.code]
if e.params:
message = message % e.params
errors.append(message)
else:
errors.extend(e.messages)
e.message = self.error_messages[e.code]
errors.extend(e.error_list)
if errors:
raise ValidationError(errors)
......@@ -974,7 +970,7 @@ class MultiValueField(Field):
# Collect all validation errors in a single list, which we'll
# raise at the end of clean(), rather than raising a single
# exception for the first error we encounter.
errors.extend(e.messages)
errors.extend(e.error_list)
if errors:
raise ValidationError(errors)
......
......@@ -389,17 +389,11 @@ class BaseModelForm(BaseForm):
if isinstance(field, InlineForeignKeyField):
exclude.append(f_name)
# Clean the model instance's fields.
try:
self.instance.clean_fields(exclude=exclude)
self.instance.full_clean(exclude=exclude,
validate_unique=False)
except ValidationError as e:
self._update_errors(e.message_dict)
# Call the model instance's clean method.
try:
self.instance.clean()
except ValidationError as e:
self._update_errors({NON_FIELD_ERRORS: e.messages})
self._update_errors(e)
# Validate uniqueness if needed.
if self._validate_unique:
......@@ -414,7 +408,7 @@ class BaseModelForm(BaseForm):
try:
self.instance.validate_unique(exclude=exclude)
except ValidationError as e:
self._update_errors(e.message_dict)
self._update_errors(e)
def save(self, commit=True):
"""
......
......@@ -213,7 +213,7 @@ class TestSimpleValidators(TestCase):
self.assertEqual(repr(v), str_prefix("ValidationError([%(_)s'First Problem', %(_)s'Second Problem'])"))
def test_message_dict(self):
v = ValidationError({'first': 'First Problem'})
v = ValidationError({'first': ['First Problem']})
self.assertEqual(str(v), str_prefix("{%(_)s'first': %(_)s'First Problem'}"))
self.assertEqual(repr(v), str_prefix("ValidationError({%(_)s'first': %(_)s'First Problem'})"))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment