Author: Honza_Kral
Date: 2009-06-01 10:38:58 -0500 (Mon, 01 Jun 2009)
New Revision: 10869

Added:
   django/branches/soc2009/model-validation/tests/modeltests/validation/
   
django/branches/soc2009/model-validation/tests/modeltests/validation/__init__.py
   
django/branches/soc2009/model-validation/tests/modeltests/validation/models.py
Modified:
   django/branches/soc2009/model-validation/django/core/exceptions.py
   django/branches/soc2009/model-validation/django/db/models/base.py
Log:
[soc2009/model-validation] Added clean() and validate() methods to Model.

This also called for ValidationError to also accept dicts as message.

Modified: django/branches/soc2009/model-validation/django/core/exceptions.py
===================================================================
--- django/branches/soc2009/model-validation/django/core/exceptions.py  
2009-06-01 15:38:34 UTC (rev 10868)
+++ django/branches/soc2009/model-validation/django/core/exceptions.py  
2009-06-01 15:38:58 UTC (rev 10869)
@@ -32,23 +32,33 @@
     """Some kind of problem with a model field."""
     pass
 
+NON_FIELD_ERRORS = '__all__'
 class ValidationError(Exception):
     """An error while validating data."""
     def __init__(self, message):
+        import operator
         from django.utils.encoding import force_unicode
         """
         ValidationError can be passed any object that can be printed (usually
-        a string) or a list of objects.
+        a string), a list of objects or a dictionary.
         """
+        if isinstance(message, dict):
+            self.message_dict = message
+            message = reduce(operator.add, message.values())
+
         if isinstance(message, list):
             self.messages = [force_unicode(msg) for msg in message]
         else:
             message = force_unicode(message)
             self.messages = [message]
 
+
+
     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'):
+            return repr(self.message_dict)
         return repr(self.messages)

Modified: django/branches/soc2009/model-validation/django/db/models/base.py
===================================================================
--- django/branches/soc2009/model-validation/django/db/models/base.py   
2009-06-01 15:38:34 UTC (rev 10868)
+++ django/branches/soc2009/model-validation/django/db/models/base.py   
2009-06-01 15:38:58 UTC (rev 10869)
@@ -9,7 +9,7 @@
     from sets import Set as set     # Python 2.3 fallback.
 
 import django.db.models.manager     # Imported to register signal handler.
-from django.core.exceptions import ObjectDoesNotExist, 
MultipleObjectsReturned, FieldError
+from django.core.exceptions import ObjectDoesNotExist, 
MultipleObjectsReturned, FieldError, ValidationError, NON_FIELD_ERRORS
 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
@@ -597,7 +597,37 @@
     def prepare_database_save(self, unused):
         return self.pk
 
+    def validate(self):
+        """
+        Hook for doing any extra model-wide validation after Model.clean() 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 named '__all__'.
+        """
+        pass
 
+    def clean(self):
+        """
+        Cleans all fields and raises ValidationError containing message_dict 
of 
+        all validation errors if any occur.
+        """
+        errors = {}
+        for f in self._meta.fields:
+            try:
+                # TODO: is the [sg]etattr correct?
+                setattr(self, f.attname, f.clean(getattr(self, f.attname), 
self))
+            except ValidationError, e:
+                errors[f.name] = e.messages
+        try:
+            # TODO: run this only if not errors??
+            self.validate()
+        except ValidationError, e:
+            errors[NON_FIELD_ERRORS] = e.messages
+
+        if errors:
+            raise ValidationError(errors)
+
+
 ############################################
 # HELPER FUNCTIONS (CURRIED MODEL METHODS) #
 ############################################

Added: 
django/branches/soc2009/model-validation/tests/modeltests/validation/__init__.py
===================================================================

Added: 
django/branches/soc2009/model-validation/tests/modeltests/validation/models.py
===================================================================
--- 
django/branches/soc2009/model-validation/tests/modeltests/validation/models.py  
                            (rev 0)
+++ 
django/branches/soc2009/model-validation/tests/modeltests/validation/models.py  
    2009-06-01 15:38:58 UTC (rev 10869)
@@ -0,0 +1,28 @@
+from datetime import datetime
+
+from django.core.exceptions import ValidationError
+from django.db import models
+from django.test import TestCase
+
+class ModelToValidate(models.Model):
+    name = models.CharField(max_length=100)
+    created = models.DateTimeField(default=datetime.now)
+    number = models.IntegerField()
+
+    def validate(self):
+        super(ModelToValidate, self).validate()
+        if self.number == 11:
+            raise ValidationError('Invalid number supplied!')
+
+class BaseModelValidationTests(TestCase):
+    def test_missing_required_field_raises_error(self):
+        mtv = ModelToValidate()
+        self.assertRaises(ValidationError, mtv.clean)
+    
+    def test_with_correct_value_model_validates(self):
+        mtv = ModelToValidate(number=10)
+        self.assertEqual(None, mtv.clean())
+
+    def test_custom_validate_method_is_called(self):
+        mtv = ModelToValidate(number=11)
+        self.assertRaises(ValidationError, mtv.clean)


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to