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/db/models/base.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/db/models/base.py')
| -rw-r--r-- | django/db/models/base.py | 108 |
1 files changed, 78 insertions, 30 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py index 46e1822fc5..886c74e27a 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -640,17 +640,21 @@ class Model(object): def prepare_database_save(self, unused): return self.pk - def validate(self): + def clean(self): """ Hook for doing any extra model-wide validation after clean() has been - called on every field. Any ValidationError raised by this method will - not be associated with a particular field; it will have a special-case - association with the field defined by NON_FIELD_ERRORS. + called on every field by self.clean_fields. Any ValidationError raised + by this method will not be associated with a particular field; it will + have a special-case association with the field defined by NON_FIELD_ERRORS. """ - self.validate_unique() + pass - def validate_unique(self): - unique_checks, date_checks = self._get_unique_checks() + def validate_unique(self, exclude=None): + """ + Checks unique constraints on the model and raises ``ValidationError`` + if any failed. + """ + unique_checks, date_checks = self._get_unique_checks(exclude=exclude) errors = self._perform_unique_checks(unique_checks) date_errors = self._perform_date_checks(date_checks) @@ -661,17 +665,35 @@ class Model(object): if errors: raise ValidationError(errors) - def _get_unique_checks(self): - from django.db.models.fields import FieldDoesNotExist, Field as ModelField + def _get_unique_checks(self, exclude=None): + """ + Gather a list of checks to perform. Since validate_unique could be + called from a ModelForm, some fields may have been excluded; we can't + perform a unique check on a model that is missing fields involved + in that check. + Fields that did not validate should also be exluded, but they need + to be passed in via the exclude argument. + """ + if exclude is None: + exclude = [] + unique_checks = [] + for check in self._meta.unique_together: + for name in check: + # If this is an excluded field, don't add this check. + if name in exclude: + break + else: + unique_checks.append(check) - unique_checks = list(self._meta.unique_together) - # these are checks for the unique_for_<date/year/month> + # These are checks for the unique_for_<date/year/month>. date_checks = [] # Gather a list of checks for fields declared as unique and add them to - # the list of checks. Again, skip empty fields and any that did not validate. + # the list of checks. for f in self._meta.fields: name = f.name + if name in exclude: + continue if f.unique: unique_checks.append((name,)) if f.unique_for_date: @@ -682,7 +704,6 @@ class Model(object): date_checks.append(('month', name, f.unique_for_month)) return unique_checks, date_checks - def _perform_unique_checks(self, unique_checks): errors = {} @@ -779,34 +800,61 @@ class Model(object): 'field_label': unicode(field_labels) } - def full_validate(self, exclude=[]): + def full_clean(self, exclude=None): + """ + Calls clean_fields, clean, and validate_unique, on the model, + and raises a ``ValidationError`` for any errors that occured. + """ + errors = {} + if exclude is None: + exclude = [] + + try: + self.clean_fields(exclude=exclude) + except ValidationError, e: + errors = e.update_error_dict(errors) + + # Form.clean() is run even if other validation fails, so do the + # same with Model.clean() for consistency. + try: + self.clean() + except ValidationError, e: + 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, e: + errors = e.update_error_dict(errors) + + if errors: + raise ValidationError(errors) + + def clean_fields(self, exclude=None): """ - Cleans all fields and raises ValidationError containing message_dict + Cleans all fields and raises a ValidationError containing message_dict of all validation errors if any occur. """ + if exclude is None: + exclude = [] + errors = {} for f in self._meta.fields: if f.name in exclude: continue + # Skip validation for empty fields with blank=True. The developer + # is responsible for making sure they have a valid value. + raw_value = getattr(self, f.attname) + if f.blank and raw_value in validators.EMPTY_VALUES: + continue try: - setattr(self, f.attname, f.clean(getattr(self, f.attname), self)) + setattr(self, f.attname, f.clean(raw_value, self)) except ValidationError, e: errors[f.name] = e.messages - # Form.clean() is run even if other validation fails, so do the - # same with Model.validate() for consistency. - try: - self.validate() - except ValidationError, e: - if hasattr(e, 'message_dict'): - if errors: - for k, v in e.message_dict.items(): - errors.setdefault(k, []).extend(v) - else: - errors = e.message_dict - else: - errors[NON_FIELD_ERRORS] = e.messages - if errors: raise ValidationError(errors) |
