diff options
| author | Joseph Kocherhans <joseph@jkocherhans.com> | 2010-01-12 02:29:45 +0000 |
|---|---|---|
| committer | Joseph Kocherhans <joseph@jkocherhans.com> | 2010-01-12 02:29:45 +0000 |
| commit | 2f9853b2dc90f30317e0374396f08e3d142844d2 (patch) | |
| tree | 6f5ade3551fbc6ac7caa11eae3b2087e94a0e975 /django/forms/models.py | |
| parent | 26279c572101ac1b277fc3947897cb8e840ea42e (diff) | |
Fixed #12512. Changed ModelForm to stop performing model validation on fields that are not part of the form. Thanks, Honza Kral and Ivan Sagalaev.
This reverts some admin and test changes from [12098] and also fixes #12507, #12520, #12552 and #12553.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12206 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/forms/models.py')
| -rw-r--r-- | django/forms/models.py | 67 |
1 files changed, 45 insertions, 22 deletions
diff --git a/django/forms/models.py b/django/forms/models.py index 30f1e2838c..817de5e9b2 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -9,7 +9,7 @@ from django.utils.datastructures import SortedDict from django.utils.text import get_text_list, capfirst from django.utils.translation import ugettext_lazy as _, ugettext -from django.core.exceptions import ValidationError, NON_FIELD_ERRORS, UnresolvableValidationError +from django.core.exceptions import ValidationError, NON_FIELD_ERRORS from django.core.validators import EMPTY_VALUES from util import ErrorList from forms import BaseForm, get_declared_fields @@ -250,31 +250,51 @@ class BaseModelForm(BaseForm): super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data, error_class, label_suffix, empty_permitted) + + def _get_validation_exclusions(self): + """ + For backwards-compatibility, several types of fields need to be + excluded from model validation. See the following tickets for + details: #12507, #12521, #12553 + """ + exclude = [] + # Build up a list of fields that should be excluded from model field + # validation and unique checks. + for f in self.instance._meta.fields: + field = f.name + # Exclude fields that aren't on the form. The developer may be + # adding these values to the model after form validation. + if field not in self.fields: + exclude.append(f.name) + # Exclude fields that failed form validation. There's no need for + # the model fields to validate them as well. + elif field in self._errors.keys(): + exclude.append(f.name) + # Exclude empty fields that are not required by the form. The + # underlying model field may be required, so this keeps the model + # field from raising that error. + else: + form_field = self.fields[field] + field_value = self.cleaned_data.get(field, None) + if field_value is None and not form_field.required: + exclude.append(f.name) + return exclude + def clean(self): opts = self._meta self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude) + exclude = self._get_validation_exclusions() try: - self.instance.full_validate(exclude=self._errors.keys()) + self.instance.full_clean(exclude=exclude) except ValidationError, e: for k, v in e.message_dict.items(): if k != NON_FIELD_ERRORS: self._errors.setdefault(k, ErrorList()).extend(v) - # Remove the data from the cleaned_data dict since it was invalid if k in self.cleaned_data: del self.cleaned_data[k] - if NON_FIELD_ERRORS in e.message_dict: raise ValidationError(e.message_dict[NON_FIELD_ERRORS]) - - # If model validation threw errors for fields that aren't on the - # form, the the errors cannot be corrected by the user. Displaying - # those errors would be pointless, so raise another type of - # exception that *won't* be caught and displayed by the form. - if set(e.message_dict.keys()) - set(self.fields.keys() + [NON_FIELD_ERRORS]): - raise UnresolvableValidationError(e.message_dict) - - return self.cleaned_data def save(self, commit=True): @@ -412,17 +432,20 @@ class BaseModelFormSet(BaseFormSet): self.validate_unique() def validate_unique(self): - # Iterate over the forms so that we can find one with potentially valid - # data from which to extract the error checks + # Collect unique_checks and date_checks to run from all the forms. + all_unique_checks = set() + all_date_checks = set() for form in self.forms: - if hasattr(form, 'cleaned_data'): - break - else: - return - unique_checks, date_checks = form.instance._get_unique_checks() + if not hasattr(form, 'cleaned_data'): + continue + exclude = form._get_validation_exclusions() + unique_checks, date_checks = form.instance._get_unique_checks(exclude=exclude) + all_unique_checks = all_unique_checks.union(set(unique_checks)) + all_date_checks = all_date_checks.union(set(date_checks)) + errors = [] # Do each of the unique checks (unique and unique_together) - for unique_check in unique_checks: + for unique_check in all_unique_checks: seen_data = set() for form in self.forms: # if the form doesn't have cleaned_data then we ignore it, @@ -444,7 +467,7 @@ class BaseModelFormSet(BaseFormSet): # mark the data as seen seen_data.add(row_data) # iterate over each of the date checks now - for date_check in date_checks: + for date_check in all_date_checks: seen_data = set() lookup, field, unique_for = date_check for form in self.forms: |
