Author: Honza_Kral Date: 2009-07-19 15:55:58 -0500 (Sun, 19 Jul 2009) New Revision: 11271
Modified: django/branches/soc2009/model-validation/django/db/models/base.py django/branches/soc2009/model-validation/tests/modeltests/validation/__init__.py django/branches/soc2009/model-validation/tests/modeltests/validation/models.py django/branches/soc2009/model-validation/tests/modeltests/validation/tests.py django/branches/soc2009/model-validation/tests/modeltests/validation/validators.py Log: [soc2009/model-validation] Added capacity for ComplexValidator handling to models Modified: django/branches/soc2009/model-validation/django/db/models/base.py =================================================================== --- django/branches/soc2009/model-validation/django/db/models/base.py 2009-07-19 20:55:34 UTC (rev 11270) +++ django/branches/soc2009/model-validation/django/db/models/base.py 2009-07-19 20:55:58 UTC (rev 11271) @@ -10,6 +10,7 @@ import django.db.models.manager # Imported to register signal handler. from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError, ValidationError, NON_FIELD_ERRORS +from django.core import validators from django.db.models.fields import AutoField, FieldDoesNotExist from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField from django.db.models.query import delete_objects, Q @@ -760,6 +761,20 @@ setattr(self, f.attname, f.clean(getattr(self, f.attname), self)) except ValidationError, e: errors[f.name] = e.messages + + # run complex validators after the fields have been cleaned since they + # need access to model_instance. + for f in self._meta.fields: + if f.name in errors: + continue + + value = getattr(self, f.attname) + for v in f.validators: + if isinstance(v, validators.ComplexValidator): + try: + v(value, obj=self) + except ValidationError, e: + errors.setdefault(f.name, []).extend(e.messages) try: # TODO: run this only if not errors?? self.validate() Modified: django/branches/soc2009/model-validation/tests/modeltests/validation/__init__.py =================================================================== --- django/branches/soc2009/model-validation/tests/modeltests/validation/__init__.py 2009-07-19 20:55:34 UTC (rev 11270) +++ django/branches/soc2009/model-validation/tests/modeltests/validation/__init__.py 2009-07-19 20:55:58 UTC (rev 11271) @@ -9,5 +9,13 @@ clean() except ValidationError, e: self.assertEquals(sorted(failed_fields), sorted(e.message_dict.keys())) + + def assertFieldFailsValidationWithMessage(self, clean, field_name, message): + self.assertRaises(ValidationError, clean) + try: + clean() + except ValidationError, e: + self.assertTrue(field_name in e.message_dict) + self.assertEquals(message, e.message_dict[field_name]) Modified: django/branches/soc2009/model-validation/tests/modeltests/validation/models.py =================================================================== --- django/branches/soc2009/model-validation/tests/modeltests/validation/models.py 2009-07-19 20:55:34 UTC (rev 11270) +++ django/branches/soc2009/model-validation/tests/modeltests/validation/models.py 2009-07-19 20:55:58 UTC (rev 11271) @@ -1,6 +1,7 @@ from datetime import datetime from django.core.exceptions import ValidationError +from django.core.validators import ComplexValidator from django.db import models from django.test import TestCase @@ -8,13 +9,21 @@ if value != 42: raise ValidationError('This is not the answer to life, universe and everything!') +class ValidateFieldNotEqualsOtherField(ComplexValidator): + def __init__(self, other_field): + self.other_field = other_field + + def __call__(self, value, all_values={}, obj=None): + if value == self.get_value(self.other_field, all_values, obj): + raise ValidationError("Must not equal to %r's value" % self.other_field) + class ModelToValidate(models.Model): name = models.CharField(max_length=100) created = models.DateTimeField(default=datetime.now) number = models.IntegerField() parent = models.ForeignKey('self', blank=True, null=True) email = models.EmailField(blank=True) - f_with_custom_validator = models.IntegerField(blank=True, null=True, validators=[validate_answer_to_universe]) + f_with_custom_validator = models.IntegerField(blank=True, null=True, validators=[validate_answer_to_universe, ValidateFieldNotEqualsOtherField('number')]) def validate(self): super(ModelToValidate, self).validate() Modified: django/branches/soc2009/model-validation/tests/modeltests/validation/tests.py =================================================================== --- django/branches/soc2009/model-validation/tests/modeltests/validation/tests.py 2009-07-19 20:55:34 UTC (rev 11270) +++ django/branches/soc2009/model-validation/tests/modeltests/validation/tests.py 2009-07-19 20:55:58 UTC (rev 11271) @@ -11,7 +11,7 @@ class BaseModelValidationTests(ValidationTestCase): def test_missing_required_field_raises_error(self): - mtv = ModelToValidate() + mtv = ModelToValidate(f_with_custom_validator=42) self.assertFailsValidation(mtv.clean, ['name', 'number']) def test_with_correct_value_model_validates(self): Modified: django/branches/soc2009/model-validation/tests/modeltests/validation/validators.py =================================================================== --- django/branches/soc2009/model-validation/tests/modeltests/validation/validators.py 2009-07-19 20:55:34 UTC (rev 11270) +++ django/branches/soc2009/model-validation/tests/modeltests/validation/validators.py 2009-07-19 20:55:58 UTC (rev 11271) @@ -11,4 +11,26 @@ def test_custom_validator_raises_error_for_incorrect_value(self): mtv = ModelToValidate(number=10, name='Some Name', f_with_custom_validator=12) self.assertFailsValidation(mtv.clean, ['f_with_custom_validator']) + self.assertFieldFailsValidationWithMessage( + mtv.clean, + 'f_with_custom_validator', + [u'This is not the answer to life, universe and everything!'] + ) + def test_custom_complex_validator_raises_error_for_incorrect_value(self): + mtv = ModelToValidate(number=42, name='Some Name', f_with_custom_validator=42) + self.assertFailsValidation(mtv.clean, ['f_with_custom_validator']) + self.assertFieldFailsValidationWithMessage( + mtv.clean, + 'f_with_custom_validator', + [u"Must not equal to 'number''s value"] + ) + + + def test_complex_validator_isnt_run_if_field_doesnt_clean(self): + mtv = ModelToValidate(number=32, name='Some Name', f_with_custom_validator=32) + self.assertFieldFailsValidationWithMessage( + mtv.clean, + 'f_with_custom_validator', + [u'This is not the answer to life, universe and everything!'] + ) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django updates" group. To post to this group, send email to django-updates@googlegroups.com To unsubscribe from this group, send email to django-updates+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-updates?hl=en -~----------~----~----~----~------~----~------~--~---