Author: mtredinnick
Date: 2011-08-21 17:48:53 -0700 (Sun, 21 Aug 2011)
New Revision: 16638

Added:
   django/trunk/tests/modeltests/validation/test_error_messages.py
Modified:
   django/trunk/django/db/models/fields/__init__.py
Log:
Improved error message display during validation errors.

When reporting a validation error (during model validation or fixture
loading, for example), the error messages now report the bad value as
well as the expected type. This can make identifying the offending field
and problem a bit easier.

Fixed #11595. Patch from raulcd and wildfire with supervision from
Russell.

Modified: django/trunk/django/db/models/fields/__init__.py
===================================================================
--- django/trunk/django/db/models/fields/__init__.py    2011-08-22 00:12:51 UTC 
(rev 16637)
+++ django/trunk/django/db/models/fields/__init__.py    2011-08-22 00:48:53 UTC 
(rev 16638)
@@ -462,7 +462,7 @@
 
     empty_strings_allowed = False
     default_error_messages = {
-        'invalid': _(u'This value must be an integer.'),
+        'invalid': _(u"'%s' value must be an integer."),
     }
     def __init__(self, *args, **kwargs):
         assert kwargs.get('primary_key', False) is True, "%ss must have 
primary_key=True." % self.__class__.__name__
@@ -478,7 +478,8 @@
         try:
             return int(value)
         except (TypeError, ValueError):
-            raise exceptions.ValidationError(self.error_messages['invalid'])
+            msg = self.error_messages['invalid'] % str(value)
+            raise exceptions.ValidationError(msg)
 
     def validate(self, value, model_instance):
         pass
@@ -500,7 +501,7 @@
 class BooleanField(Field):
     empty_strings_allowed = False
     default_error_messages = {
-        'invalid': _(u'This value must be either True or False.'),
+        'invalid': _(u"'%s' value must be either True or False."),
     }
     description = _("Boolean (Either True or False)")
     def __init__(self, *args, **kwargs):
@@ -521,7 +522,8 @@
             return True
         if value in ('f', 'False', '0'):
             return False
-        raise exceptions.ValidationError(self.error_messages['invalid'])
+        msg = self.error_messages['invalid'] % str(value)
+        raise exceptions.ValidationError(msg)
 
     def get_prep_lookup(self, lookup_type, value):
         # Special-case handling for filters coming from a Web request (e.g. the
@@ -753,7 +755,7 @@
 class DecimalField(Field):
     empty_strings_allowed = False
     default_error_messages = {
-        'invalid': _(u'This value must be a decimal number.'),
+        'invalid': _(u"'%s' value must be a decimal number."),
     }
     description = _("Decimal number")
 
@@ -770,7 +772,8 @@
         try:
             return decimal.Decimal(value)
         except decimal.InvalidOperation:
-            raise exceptions.ValidationError(self.error_messages['invalid'])
+            msg = self.error_messages['invalid'] % str(value)
+            raise exceptions.ValidationError(msg)
 
     def _format(self, value):
         if isinstance(value, basestring) or value is None:
@@ -848,7 +851,7 @@
 class FloatField(Field):
     empty_strings_allowed = False
     default_error_messages = {
-        'invalid': _("This value must be a float."),
+        'invalid': _("'%s' value must be a float."),
     }
     description = _("Floating point number")
 
@@ -866,7 +869,8 @@
         try:
             return float(value)
         except (TypeError, ValueError):
-            raise exceptions.ValidationError(self.error_messages['invalid'])
+            msg = self.error_messages['invalid'] % str(value)
+            raise exceptions.ValidationError(msg)
 
     def formfield(self, **kwargs):
         defaults = {'form_class': forms.FloatField}
@@ -876,7 +880,7 @@
 class IntegerField(Field):
     empty_strings_allowed = False
     default_error_messages = {
-        'invalid': _("This value must be an integer."),
+        'invalid': _("'%s' value must be an integer."),
     }
     description = _("Integer")
 
@@ -900,7 +904,8 @@
         try:
             return int(value)
         except (TypeError, ValueError):
-            raise exceptions.ValidationError(self.error_messages['invalid'])
+            msg = self.error_messages['invalid'] % str(value)
+            raise exceptions.ValidationError(msg)
 
     def formfield(self, **kwargs):
         defaults = {'form_class': forms.IntegerField}
@@ -981,7 +986,7 @@
 class NullBooleanField(Field):
     empty_strings_allowed = False
     default_error_messages = {
-        'invalid': _("This value must be either None, True or False."),
+        'invalid': _("'%s' value must be either None, True or False."),
     }
     description = _("Boolean (Either True, False or None)")
 
@@ -1004,7 +1009,8 @@
             return True
         if value in ('f', 'False', '0'):
             return False
-        raise exceptions.ValidationError(self.error_messages['invalid'])
+        msg = self.error_messages['invalid'] % str(value)
+        raise exceptions.ValidationError(msg)
 
     def get_prep_lookup(self, lookup_type, value):
         # Special-case handling for filters coming from a Web request (e.g. the

Added: django/trunk/tests/modeltests/validation/test_error_messages.py
===================================================================
--- django/trunk/tests/modeltests/validation/test_error_messages.py             
                (rev 0)
+++ django/trunk/tests/modeltests/validation/test_error_messages.py     
2011-08-22 00:48:53 UTC (rev 16638)
@@ -0,0 +1,57 @@
+from django.core.exceptions import ValidationError
+from django.utils.unittest import TestCase
+from django.db import models
+
+
+class ValidationMessagesTest(TestCase):
+
+    def test_autofield_field_raises_error_message(self):
+        f = models.AutoField(primary_key=True)
+        self.assertRaises(ValidationError, f.clean, 'foo', None)
+        try:
+            f.clean('foo', None)
+        except ValidationError, e:
+            self.assertEqual(e.messages, [u"'foo' value must be an integer."])
+
+    def test_integer_field_raises_error_message(self):
+        f = models.IntegerField()
+        self.assertRaises(ValidationError, f.clean, 'foo', None)
+        try:
+            f.clean('foo', None)
+        except ValidationError, e:
+            self.assertEqual(e.messages, [u"'foo' value must be an integer."])
+
+    def test_boolean_field_raises_error_message(self):
+        f = models.BooleanField()
+        self.assertRaises(ValidationError, f.clean, 'foo', None)
+        try:
+            f.clean('foo', None)
+        except ValidationError, e:
+            self.assertEqual(e.messages,
+                        [u"'foo' value must be either True or False."])
+
+    def test_float_field_raises_error_message(self):
+        f = models.FloatField()
+        self.assertRaises(ValidationError, f.clean, 'foo', None)
+        try:
+            f.clean('foo', None)
+        except ValidationError, e:
+            self.assertEqual(e.messages, [u"'foo' value must be a float."])
+
+    def test_decimal_field_raises_error_message(self):
+        f = models.DecimalField()
+        self.assertRaises(ValidationError, f.clean, 'foo', None)
+        try:
+            f.clean('foo', None)
+        except ValidationError, e:
+            self.assertEqual(e.messages,
+                        [u"'foo' value must be a decimal number."])
+
+    def test_null_boolean_field_raises_error_message(self):
+        f = models.NullBooleanField()
+        self.assertRaises(ValidationError, f.clean, 'foo', None)
+        try:
+            f.clean('foo', None)
+        except ValidationError, e:
+            self.assertEqual(e.messages,
+                        [u"'foo' value must be either None, True or False."])

-- 
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