diff --git a/django/core/validators.py b/django/core/validators.py index 8ac9a96cc7..46b1e4fc36 100644 --- a/django/core/validators.py +++ b/django/core/validators.py @@ -7,7 +7,7 @@ from django.utils.encoding import smart_unicode # These values, if given to to_python(), will trigger the self.required check. EMPTY_VALUES = (None, '') -def validate_integer(value, all_values={}, model_instance=None): +def validate_integer(value): try: int(value) except (ValueError, TypeError), e: @@ -18,6 +18,28 @@ email_re = re.compile( r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string r')@(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain -def validate_email(value, all_values={}, model_instance=None): +def validate_email(value): if not email_re.search(smart_unicode(value)): raise ValidationError(_(u'Enter a valid e-mail address.')) + +class ComplexValidator(object): + def get_value(self, name, all_values, obj): + assert all_values or obj, "Either all_values or obj must be supplied" + + if all_values: + return all_values.get(name, None) + if obj: + return getattr(obj, name, None) + + + def __call__(self, value, all_values={}, obj=None): + raise NotImplementedError() + +class RequiredIfOtherFieldBlank(ComplexValidator): + def __init__(self, other_field): + self.other_field = other_field + + def __call__(self, value, all_values={}, obj=None): + if self.get_value(self.other_field, all_values, obj) in EMPTY_VALUES: + if value in EMPTY_VALUES: + raise ValidationError('This field is required if %n is blank.' % self.other_field) diff --git a/django/forms/fields.py b/django/forms/fields.py index 9446ed2eea..d65edd7047 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -119,6 +119,11 @@ class Field(object): def validate(self, value): if value in EMPTY_VALUES and self.required: raise ValidationError(self.error_messages['required']) + for v in self.validators: + # don't run complex validators since they need all_values + # and must therefore be run on the form level + if not isinstance(v, validators.ComplexValidator): + v(value) def clean(self, value): diff --git a/django/forms/forms.py b/django/forms/forms.py index b5c0fc06e0..912fd7c031 100644 --- a/django/forms/forms.py +++ b/django/forms/forms.py @@ -5,6 +5,7 @@ Form classes from copy import deepcopy from django.core.exceptions import ValidationError +from django.core.validators import ComplexValidator from django.utils.datastructures import SortedDict from django.utils.html import conditional_escape from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode @@ -254,6 +255,9 @@ class BaseForm(StrAndUnicode): if not name in self.cleaned_data: continue for v in field.validators: + # skip noncomplex validators, they have already been run on the Field + if not isinstance(v, ComplexValidator): + continue try: v(self.cleaned_data[name], all_values=self.cleaned_data) except ValidationError, e: