Ticket #3457: newforms_error_messages.5.patch

File newforms_error_messages.5.patch, 41.2 KB (added by Gary Wilson, 17 years ago)

removed my changes from testcases.py I made during testing

  • django/newforms/util.py

     
    11from django.utils.html import escape
    2 from django.utils.encoding import smart_unicode, StrAndUnicode
     2from django.utils.encoding import smart_unicode, force_unicode, StrAndUnicode
    33from django.utils.functional import Promise
    44
    55def flatatt(attrs):
     
    4242        if not self: return u''
    4343        return u'\n'.join([u'* %s' % smart_unicode(e) for e in self])
    4444
     45    def __repr__(self):
     46        return repr([force_unicode(e) for e in self])
     47
    4548class ValidationError(Exception):
    4649    def __init__(self, message):
    4750        "ValidationError can be passed a string or a list."
    4851        if isinstance(message, list):
    4952            self.messages = ErrorList([smart_unicode(msg) for msg in message])
    5053        else:
    51             assert isinstance(message, (basestring, Promise)), ("%s should be a basestring or lazy translation" % repr(message))
    5254            message = smart_unicode(message)
    5355            self.messages = ErrorList([message])
    5456
  • django/newforms/fields.py

     
    77import re
    88import time
    99
    10 from django.utils.translation import ugettext
     10from django.utils.translation import ugettext_lazy
    1111from django.utils.encoding import StrAndUnicode, smart_unicode
    1212
    1313from util import ErrorList, ValidationError
     
    4545class Field(object):
    4646    widget = TextInput # Default widget to use when rendering this type of Field.
    4747    hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden".
     48    default_error_messages = {
     49        'required': ugettext_lazy(u'This field is required.'),
     50        'invalid': ugettext_lazy(u'Enter a valid value.'),
     51    }
    4852
    4953    # Tracks each time a Field instance is created. Used to retain order.
    5054    creation_counter = 0
    5155
    52     def __init__(self, required=True, widget=None, label=None, initial=None, help_text=None):
     56    def __init__(self, required=True, widget=None, label=None, initial=None,
     57                 help_text=None, error_messages=None):
    5358        # required -- Boolean that specifies whether the field is required.
    5459        #             True by default.
    5560        # widget -- A Widget class, or instance of a Widget class, that should
     
    8287        self.creation_counter = Field.creation_counter
    8388        Field.creation_counter += 1
    8489
     90        self.error_messages = self._build_error_messages(error_messages)
     91
     92    def _build_error_messages(self, extra_error_messages):
     93        error_messages = {}
     94        def get_default_error_messages(klass):
     95            for base_class in klass.__bases__:
     96                get_default_error_messages(base_class)
     97            if hasattr(klass, 'default_error_messages'):
     98                error_messages.update(klass.default_error_messages)
     99        get_default_error_messages(self.__class__)
     100        if extra_error_messages:
     101            error_messages.update(extra_error_messages)
     102        return error_messages
     103
    85104    def clean(self, value):
    86105        """
    87106        Validates the given value and returns its "cleaned" value as an
     
    90109        Raises ValidationError for any errors.
    91110        """
    92111        if self.required and value in EMPTY_VALUES:
    93             raise ValidationError(ugettext(u'This field is required.'))
     112            raise ValidationError(self.error_messages['required'])
    94113        return value
    95114
    96115    def widget_attrs(self, widget):
     
    108127        return result
    109128
    110129class CharField(Field):
     130    default_error_messages = {
     131        'max_length': ugettext_lazy(u'Ensure this value has at most %(max)d characters (it has %(length)d).'),
     132        'min_length': ugettext_lazy(u'Ensure this value has at least %(min)d characters (it has %(length)d).'),
     133    }
     134
    111135    def __init__(self, max_length=None, min_length=None, *args, **kwargs):
    112136        self.max_length, self.min_length = max_length, min_length
    113137        super(CharField, self).__init__(*args, **kwargs)
     
    120144        value = smart_unicode(value)
    121145        value_length = len(value)
    122146        if self.max_length is not None and value_length > self.max_length:
    123             raise ValidationError(ugettext(u'Ensure this value has at most %(max)d characters (it has %(length)d).') % {'max': self.max_length, 'length': value_length})
     147            raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length})
    124148        if self.min_length is not None and value_length < self.min_length:
    125             raise ValidationError(ugettext(u'Ensure this value has at least %(min)d characters (it has %(length)d).') % {'min': self.min_length, 'length': value_length})
     149            raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length})
    126150        return value
    127151
    128152    def widget_attrs(self, widget):
     
    131155            return {'maxlength': str(self.max_length)}
    132156
    133157class IntegerField(Field):
     158    default_error_messages = {
     159        'invalid': ugettext_lazy(u'Enter a whole number.'),
     160        'max_value': ugettext_lazy(u'Ensure this value is less than or equal to %s.'),
     161        'min_value': ugettext_lazy(u'Ensure this value is greater than or equal to %s.'),
     162    }
     163
    134164    def __init__(self, max_value=None, min_value=None, *args, **kwargs):
    135165        self.max_value, self.min_value = max_value, min_value
    136166        super(IntegerField, self).__init__(*args, **kwargs)
     
    146176        try:
    147177            value = int(value)
    148178        except (ValueError, TypeError):
    149             raise ValidationError(ugettext(u'Enter a whole number.'))
     179            raise ValidationError(self.error_messages['invalid'])
    150180        if self.max_value is not None and value > self.max_value:
    151             raise ValidationError(ugettext(u'Ensure this value is less than or equal to %s.') % self.max_value)
     181            raise ValidationError(self.error_messages['max_value'] % self.max_value)
    152182        if self.min_value is not None and value < self.min_value:
    153             raise ValidationError(ugettext(u'Ensure this value is greater than or equal to %s.') % self.min_value)
     183            raise ValidationError(self.error_messages['min_value'] % self.min_value)
    154184        return value
    155185
    156186class FloatField(Field):
     187    default_error_messages = {
     188        'invalid': ugettext_lazy(u'Enter a number.'),
     189        'max_value': ugettext_lazy(u'Ensure this value is less than or equal to %s.'),
     190        'min_value': ugettext_lazy(u'Ensure this value is greater than or equal to %s.'),
     191    }
     192
    157193    def __init__(self, max_value=None, min_value=None, *args, **kwargs):
    158194        self.max_value, self.min_value = max_value, min_value
    159195        Field.__init__(self, *args, **kwargs)
     
    169205        try:
    170206            value = float(value)
    171207        except (ValueError, TypeError):
    172             raise ValidationError(ugettext('Enter a number.'))
     208            raise ValidationError(self.error_messages['invalid'])
    173209        if self.max_value is not None and value > self.max_value:
    174             raise ValidationError(ugettext('Ensure this value is less than or equal to %s.') % self.max_value)
     210            raise ValidationError(self.error_messages['max_value'] % self.max_value)
    175211        if self.min_value is not None and value < self.min_value:
    176             raise ValidationError(ugettext('Ensure this value is greater than or equal to %s.') % self.min_value)
     212            raise ValidationError(self.error_messages['min_value'] % self.min_value)
    177213        return value
    178214
    179215class DecimalField(Field):
     216    default_error_messages = {
     217        'invalid': ugettext_lazy(u'Enter a number.'),
     218        'max_value': ugettext_lazy(u'Ensure this value is less than or equal to %s.'),
     219        'min_value': ugettext_lazy(u'Ensure this value is greater than or equal to %s.'),
     220        'max_digits': ugettext_lazy('Ensure that there are no more than %s digits in total.'),
     221        'max_decimal_places': ugettext_lazy('Ensure that there are no more than %s decimal places.'),
     222        'max_whole_digits': ugettext_lazy('Ensure that there are no more than %s digits before the decimal point.')
     223    }
     224
    180225    def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
    181226        self.max_value, self.min_value = max_value, min_value
    182227        self.max_digits, self.decimal_places = max_digits, decimal_places
     
    196241        try:
    197242            value = Decimal(value)
    198243        except DecimalException:
    199             raise ValidationError(ugettext('Enter a number.'))
     244            raise ValidationError(self.error_messages['invalid'])
    200245        pieces = str(value).lstrip("-").split('.')
    201246        decimals = (len(pieces) == 2) and len(pieces[1]) or 0
    202247        digits = len(pieces[0])
    203248        if self.max_value is not None and value > self.max_value:
    204             raise ValidationError(ugettext('Ensure this value is less than or equal to %s.') % self.max_value)
     249            raise ValidationError(self.error_messages['max_value'] % self.max_value)
    205250        if self.min_value is not None and value < self.min_value:
    206             raise ValidationError(ugettext('Ensure this value is greater than or equal to %s.') % self.min_value)
     251            raise ValidationError(self.error_messages['min_value'] % self.min_value)
    207252        if self.max_digits is not None and (digits + decimals) > self.max_digits:
    208             raise ValidationError(ugettext('Ensure that there are no more than %s digits in total.') % self.max_digits)
     253            raise ValidationError(self.error_messages['max_digits'] % self.max_digits)
    209254        if self.decimal_places is not None and decimals > self.decimal_places:
    210             raise ValidationError(ugettext('Ensure that there are no more than %s decimal places.') % self.decimal_places)
     255            raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places)
    211256        if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places):
    212             raise ValidationError(ugettext('Ensure that there are no more than %s digits before the decimal point.') % (self.max_digits - self.decimal_places))
     257            raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places))
    213258        return value
    214259
    215260DEFAULT_DATE_INPUT_FORMATS = (
     
    221266)
    222267
    223268class DateField(Field):
     269    default_error_messages = {
     270        'invalid': ugettext_lazy(u'Enter a valid date.'),
     271    }
     272
    224273    def __init__(self, input_formats=None, *args, **kwargs):
    225274        super(DateField, self).__init__(*args, **kwargs)
    226275        self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS
     
    242291                return datetime.date(*time.strptime(value, format)[:3])
    243292            except ValueError:
    244293                continue
    245         raise ValidationError(ugettext(u'Enter a valid date.'))
     294        raise ValidationError(self.error_messages['invalid'])
    246295
    247296DEFAULT_TIME_INPUT_FORMATS = (
    248297    '%H:%M:%S',     # '14:30:59'
     
    250299)
    251300
    252301class TimeField(Field):
     302    default_error_messages = {
     303        'invalid': ugettext_lazy(u'Enter a valid time.')
     304    }
     305
    253306    def __init__(self, input_formats=None, *args, **kwargs):
    254307        super(TimeField, self).__init__(*args, **kwargs)
    255308        self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS
     
    269322                return datetime.time(*time.strptime(value, format)[3:6])
    270323            except ValueError:
    271324                continue
    272         raise ValidationError(ugettext(u'Enter a valid time.'))
     325        raise ValidationError(self.error_messages['invalid'])
    273326
    274327DEFAULT_DATETIME_INPUT_FORMATS = (
    275328    '%Y-%m-%d %H:%M:%S',     # '2006-10-25 14:30:59'
     
    284337)
    285338
    286339class DateTimeField(Field):
     340    default_error_messages = {
     341        'invalid': ugettext_lazy(u'Enter a valid date/time.'),
     342    }
     343
    287344    def __init__(self, input_formats=None, *args, **kwargs):
    288345        super(DateTimeField, self).__init__(*args, **kwargs)
    289346        self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
     
    305362                return datetime.datetime(*time.strptime(value, format)[:6])
    306363            except ValueError:
    307364                continue
    308         raise ValidationError(ugettext(u'Enter a valid date/time.'))
     365        raise ValidationError(self.error_messages['invalid'])
    309366
    310367class RegexField(CharField):
    311368    def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs):
     
    314371        error_message is an optional error message to use, if
    315372        'Enter a valid value' is too generic for you.
    316373        """
     374        # error_message is just kept for backwards compatibility:
     375        if error_message:
     376            error_messages = kwargs.get('error_messages') or {}
     377            error_messages['invalid'] = error_message
     378            kwargs['error_messages'] = error_messages
    317379        super(RegexField, self).__init__(max_length, min_length, *args, **kwargs)
    318380        if isinstance(regex, basestring):
    319381            regex = re.compile(regex)
    320382        self.regex = regex
    321         self.error_message = error_message or ugettext(u'Enter a valid value.')
    322383
    323384    def clean(self, value):
    324385        """
     
    329390        if value == u'':
    330391            return value
    331392        if not self.regex.search(value):
    332             raise ValidationError(self.error_message)
     393            raise ValidationError(self.error_messages['invalid'])
    333394        return value
    334395
    335396email_re = re.compile(
     
    338399    r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE)  # domain
    339400
    340401class EmailField(RegexField):
     402    default_error_messages = {
     403        'invalid': ugettext_lazy(u'Enter a valid e-mail address.'),
     404    }
     405
    341406    def __init__(self, max_length=None, min_length=None, *args, **kwargs):
    342         RegexField.__init__(self, email_re, max_length, min_length,
    343             ugettext(u'Enter a valid e-mail address.'), *args, **kwargs)
     407        RegexField.__init__(self, email_re, max_length, min_length, *args,
     408                            **kwargs)
    344409
    345410try:
    346411    from django.conf import settings
     
    364429
    365430class FileField(Field):
    366431    widget = FileInput
     432    default_error_messages = {
     433        'invalid': ugettext_lazy(u"No file was submitted. Check the encoding type on the form."),
     434        'missing': ugettext_lazy(u"No file was submitted."),
     435        'empty': ugettext_lazy(u"The submitted file is empty."),
     436    }
     437
    367438    def __init__(self, *args, **kwargs):
    368439        super(FileField, self).__init__(*args, **kwargs)
    369440
     
    374445        try:
    375446            f = UploadedFile(data['filename'], data['content'])
    376447        except TypeError:
    377             raise ValidationError(ugettext(u"No file was submitted. Check the encoding type on the form."))
     448            raise ValidationError(self.error_messages['invalid'])
    378449        except KeyError:
    379             raise ValidationError(ugettext(u"No file was submitted."))
     450            raise ValidationError(self.error_messages['missing'])
    380451        if not f.content:
    381             raise ValidationError(ugettext(u"The submitted file is empty."))
     452            raise ValidationError(self.error_messages['empty'])
    382453        return f
    383454
    384455class ImageField(FileField):
     456    default_error_messages = {
     457        'invalid_image': ugettext_lazy(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."),
     458    }
     459
    385460    def clean(self, data):
    386461        """
    387462        Checks that the file-upload field data contains a valid image (GIF, JPG,
     
    402477            trial_image = Image.open(StringIO(f.content))
    403478            trial_image.verify()
    404479        except Exception: # Python Imaging Library doesn't recognize it as an image
    405             raise ValidationError(ugettext(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."))
     480            raise ValidationError(self.error_messages['invalid_image'])
    406481        return f
    407482
    408483url_re = re.compile(
     
    414489    r'(?:/?|/\S+)$', re.IGNORECASE)
    415490
    416491class URLField(RegexField):
     492    default_error_messages = {
     493        'invalid': ugettext_lazy(u'Enter a valid URL.'),
     494        'invalid_link': ugettext_lazy(u'This URL appears to be a broken link.'),
     495    }
     496
    417497    def __init__(self, max_length=None, min_length=None, verify_exists=False,
    418498            validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
    419         super(URLField, self).__init__(url_re, max_length, min_length, ugettext(u'Enter a valid URL.'), *args, **kwargs)
     499        super(URLField, self).__init__(url_re, max_length, min_length, *args,
     500                                       **kwargs)
    420501        self.verify_exists = verify_exists
    421502        self.user_agent = validator_user_agent
    422503
     
    441522                req = urllib2.Request(value, None, headers)
    442523                u = urllib2.urlopen(req)
    443524            except ValueError:
    444                 raise ValidationError(ugettext(u'Enter a valid URL.'))
     525                raise ValidationError(self.error_messages['invalid'])
    445526            except: # urllib2.URLError, httplib.InvalidURL, etc.
    446                 raise ValidationError(ugettext(u'This URL appears to be a broken link.'))
     527                raise ValidationError(self.error_messages['invalid_link'])
    447528        return value
    448529
    449530class BooleanField(Field):
     
    466547
    467548class ChoiceField(Field):
    468549    widget = Select
     550    default_error_messages = {
     551        'invalid_choice': ugettext_lazy(u'Select a valid choice. That choice is not one of the available choices.'),
     552    }
    469553
    470     def __init__(self, choices=(), required=True, widget=None, label=None, initial=None, help_text=None):
    471         super(ChoiceField, self).__init__(required, widget, label, initial, help_text)
     554    def __init__(self, choices=(), required=True, widget=None, label=None,
     555                 initial=None, help_text=None, *args, **kwargs):
     556        super(ChoiceField, self).__init__(required, widget, label, initial,
     557                                          help_text, *args, **kwargs)
    472558        self.choices = choices
    473559
    474560    def _get_choices(self):
     
    494580            return value
    495581        valid_values = set([smart_unicode(k) for k, v in self.choices])
    496582        if value not in valid_values:
    497             raise ValidationError(ugettext(u'Select a valid choice. That choice is not one of the available choices.'))
     583            raise ValidationError(self.error_messages['invalid_choice'] % {'value': value})
    498584        return value
    499585
    500586class MultipleChoiceField(ChoiceField):
    501587    hidden_widget = MultipleHiddenInput
    502588    widget = SelectMultiple
     589    default_error_messages = {
     590        'invalid_choice': ugettext_lazy(u'Select a valid choice. %(value)s is not one of the available choices.'),
     591        'invalid_list': ugettext_lazy(u'Enter a list of values.'),
     592    }
    503593
    504594    def clean(self, value):
    505595        """
    506596        Validates that the input is a list or tuple.
    507597        """
    508598        if self.required and not value:
    509             raise ValidationError(ugettext(u'This field is required.'))
     599            raise ValidationError(self.error_messages['required'])
    510600        elif not self.required and not value:
    511601            return []
    512602        if not isinstance(value, (list, tuple)):
    513             raise ValidationError(ugettext(u'Enter a list of values.'))
     603            raise ValidationError(self.error_messages['invalid_list'])
    514604        new_value = [smart_unicode(val) for val in value]
    515605        # Validate that each value in the value list is in self.choices.
    516606        valid_values = set([smart_unicode(k) for k, v in self.choices])
    517607        for val in new_value:
    518608            if val not in valid_values:
    519                 raise ValidationError(ugettext(u'Select a valid choice. %s is not one of the available choices.') % val)
     609                raise ValidationError(self.error_messages['invalid_choice'] % {'value': val})
    520610        return new_value
    521611
    522612class ComboField(Field):
     
    559649
    560650    You'll probably want to use this with MultiWidget.
    561651    """
     652    default_error_messages = {
     653        'invalid': ugettext_lazy(u'Enter a list of values.'),
     654    }
    562655    def __init__(self, fields=(), *args, **kwargs):
    563656        super(MultiValueField, self).__init__(*args, **kwargs)
    564657        # Set 'required' to False on the individual fields, because the
     
    582675        if not value or isinstance(value, (list, tuple)):
    583676            if not value or not [v for v in value if v not in EMPTY_VALUES]:
    584677                if self.required:
    585                     raise ValidationError(ugettext(u'This field is required.'))
     678                    raise ValidationError(self.error_messages['required'])
    586679                else:
    587680                    return self.compress([])
    588681        else:
    589             raise ValidationError(ugettext(u'Enter a list of values.'))
     682            raise ValidationError(self.error_messages['invalid'])
    590683        for i, field in enumerate(self.fields):
    591684            try:
    592685                field_value = value[i]
    593686            except IndexError:
    594687                field_value = None
    595688            if self.required and field_value in EMPTY_VALUES:
    596                 raise ValidationError(ugettext(u'This field is required.'))
     689                raise ValidationError(self.error_messages['required'])
    597690            try:
    598691                clean_data.append(field.clean(field_value))
    599692            except ValidationError, e:
     
    617710        raise NotImplementedError('Subclasses must implement this method.')
    618711
    619712class SplitDateTimeField(MultiValueField):
     713    default_error_messages = {
     714        'invalid_date': ugettext_lazy(u'Enter a valid date.'),
     715        'invalid_time': ugettext_lazy(u'Enter a valid time.'),
     716    }
    620717    def __init__(self, *args, **kwargs):
    621         fields = (DateField(), TimeField())
     718        e = self.default_error_messages.copy()
     719        if 'error_messages' in kwargs:
     720            e.update(kwargs['error_messages'])
     721        fields = (DateField(error_messages={'invalid': e['invalid_date']}),
     722                  TimeField(error_messages={'invalid': e['invalid_time']}))
    622723        super(SplitDateTimeField, self).__init__(fields, *args, **kwargs)
    623724
    624725    def compress(self, data_list):
     
    626727            # Raise a validation error if time or date is empty
    627728            # (possible if SplitDateTimeField has required=False).
    628729            if data_list[0] in EMPTY_VALUES:
    629                 raise ValidationError(ugettext(u'Enter a valid date.'))
     730                raise ValidationError(self.error_messages['invalid_date'])
    630731            if data_list[1] in EMPTY_VALUES:
    631                 raise ValidationError(ugettext(u'Enter a valid time.'))
     732                raise ValidationError(self.error_messages['invalid_time'])
    632733            return datetime.datetime.combine(*data_list)
    633734        return None
  • tests/regressiontests/forms/util.py

     
    4242# Can take a mixture in a list.
    4343>>> print ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages
    4444<ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul>
     45
     46>>> class VeryBadError:
     47...     def __str__(self): return "A very bad error."
     48
     49# Can take a non-string.
     50>>> print ValidationError(VeryBadError()).messages
     51<ul class="errorlist"><li>A very bad error.</li></ul>
    4552"""
  • tests/regressiontests/forms/tests.py

     
    940940>>> f.clean('1234567890a')
    941941u'1234567890a'
    942942
     943Custom error messages
     944>>> e = {'required': 'REQUIRED'}
     945>>> e['min_length'] = 'LENGTH %(length)s, MIN LENGTH %(min)s'
     946>>> e['max_length'] = 'LENGTH %(length)s, MAX LENGTH %(max)s'
     947>>> f = CharField(min_length=5, max_length=10, error_messages=e)
     948>>> f.clean('')
     949Traceback (most recent call last):
     950...
     951ValidationError: [u'REQUIRED']
     952>>> f.clean('1234')
     953Traceback (most recent call last):
     954...
     955ValidationError: [u'LENGTH 4, MIN LENGTH 5']
     956>>> f.clean('12345678901')
     957Traceback (most recent call last):
     958...
     959ValidationError: [u'LENGTH 11, MAX LENGTH 10']
     960
    943961# IntegerField ################################################################
    944962
    945963>>> f = IntegerField()
     
    10651083...
    10661084ValidationError: [u'Ensure this value is less than or equal to 20.']
    10671085
     1086Custom error messages
     1087>>> e = {'required': 'REQUIRED'}
     1088>>> e['invalid'] = 'INVALID'
     1089>>> e['min_value'] = 'MIN VALUE IS %s'
     1090>>> e['max_value'] = 'MAX VALUE IS %s'
     1091>>> f = IntegerField(min_value=5, max_value=10, error_messages=e)
     1092>>> f.clean('')
     1093Traceback (most recent call last):
     1094...
     1095ValidationError: [u'REQUIRED']
     1096>>> f.clean('abc')
     1097Traceback (most recent call last):
     1098...
     1099ValidationError: [u'INVALID']
     1100>>> f.clean('4')
     1101Traceback (most recent call last):
     1102...
     1103ValidationError: [u'MIN VALUE IS 5']
     1104>>> f.clean('11')
     1105Traceback (most recent call last):
     1106...
     1107ValidationError: [u'MAX VALUE IS 10']
     1108
    10681109# FloatField ##################################################################
    10691110
    10701111>>> f = FloatField()
     
    11231164>>> f.clean('0.5')
    112411650.5
    11251166
     1167Custom error messages
     1168>>> e = {'required': 'REQUIRED'}
     1169>>> e['invalid'] = 'INVALID'
     1170>>> e['min_value'] = 'MIN VALUE IS %s'
     1171>>> e['max_value'] = 'MAX VALUE IS %s'
     1172>>> f = FloatField(min_value=5, max_value=10, error_messages=e)
     1173>>> f.clean('')
     1174Traceback (most recent call last):
     1175...
     1176ValidationError: [u'REQUIRED']
     1177>>> f.clean('abc')
     1178Traceback (most recent call last):
     1179...
     1180ValidationError: [u'INVALID']
     1181>>> f.clean('4')
     1182Traceback (most recent call last):
     1183...
     1184ValidationError: [u'MIN VALUE IS 5']
     1185>>> f.clean('11')
     1186Traceback (most recent call last):
     1187...
     1188ValidationError: [u'MAX VALUE IS 10']
     1189
    11261190# DecimalField ################################################################
    11271191
    11281192>>> f = DecimalField(max_digits=4, decimal_places=2)
     
    12211285>>> f.clean('00.50')
    12221286Decimal("0.50")
    12231287
     1288Custom error messages
     1289>>> e = {'required': 'REQUIRED'}
     1290>>> e['invalid'] = 'INVALID'
     1291>>> e['min_value'] = 'MIN VALUE IS %s'
     1292>>> e['max_value'] = 'MAX VALUE IS %s'
     1293>>> e['max_digits'] = 'MAX DIGITS IS %s'
     1294>>> e['max_decimal_places'] = 'MAX DP IS %s'
     1295>>> e['max_whole_digits'] = 'MAX DIGITS BEFORE DP IS %s'
     1296>>> f = DecimalField(min_value=5, max_value=10, error_messages=e)
     1297>>> f2 = DecimalField(max_digits=4, decimal_places=2, error_messages=e)
     1298>>> f.clean('')
     1299Traceback (most recent call last):
     1300...
     1301ValidationError: [u'REQUIRED']
     1302>>> f.clean('abc')
     1303Traceback (most recent call last):
     1304...
     1305ValidationError: [u'INVALID']
     1306>>> f.clean('4')
     1307Traceback (most recent call last):
     1308...
     1309ValidationError: [u'MIN VALUE IS 5']
     1310>>> f.clean('11')
     1311Traceback (most recent call last):
     1312...
     1313ValidationError: [u'MAX VALUE IS 10']
     1314>>> f2.clean('123.45')
     1315Traceback (most recent call last):
     1316...
     1317ValidationError: [u'MAX DIGITS IS 4']
     1318>>> f2.clean('1.234')
     1319Traceback (most recent call last):
     1320...
     1321ValidationError: [u'MAX DP IS 2']
     1322>>> f2.clean('123.4')
     1323Traceback (most recent call last):
     1324...
     1325ValidationError: [u'MAX DIGITS BEFORE DP IS 2']
     1326
    12241327# DateField ###################################################################
    12251328
    12261329>>> import datetime
     
    12981401...
    12991402ValidationError: [u'Enter a valid date.']
    13001403
     1404Custom error messages
     1405>>> e = {'required': 'REQUIRED'}
     1406>>> e['invalid'] = 'INVALID'
     1407>>> f = DateField(error_messages=e)
     1408>>> f.clean('')
     1409Traceback (most recent call last):
     1410...
     1411ValidationError: [u'REQUIRED']
     1412>>> f.clean('abc')
     1413Traceback (most recent call last):
     1414...
     1415ValidationError: [u'INVALID']
     1416
    13011417# TimeField ###################################################################
    13021418
    13031419>>> import datetime
     
    13371453...
    13381454ValidationError: [u'Enter a valid time.']
    13391455
     1456Custom error messages
     1457>>> e = {'required': 'REQUIRED'}
     1458>>> e['invalid'] = 'INVALID'
     1459>>> f = TimeField(error_messages=e)
     1460>>> f.clean('')
     1461Traceback (most recent call last):
     1462...
     1463ValidationError: [u'REQUIRED']
     1464>>> f.clean('abc')
     1465Traceback (most recent call last):
     1466...
     1467ValidationError: [u'INVALID']
     1468
    13401469# DateTimeField ###############################################################
    13411470
    13421471>>> import datetime
     
    14101539>>> repr(f.clean(''))
    14111540'None'
    14121541
     1542Custom error messages
     1543>>> e = {'required': 'REQUIRED'}
     1544>>> e['invalid'] = 'INVALID'
     1545>>> f = DateTimeField(error_messages=e)
     1546>>> f.clean('')
     1547Traceback (most recent call last):
     1548...
     1549ValidationError: [u'REQUIRED']
     1550>>> f.clean('abc')
     1551Traceback (most recent call last):
     1552...
     1553ValidationError: [u'INVALID']
     1554
    14131555# RegexField ##################################################################
    14141556
    14151557>>> f = RegexField('^\d[A-F]\d$')
     
    15011643...
    15021644ValidationError: [u'Enter a valid value.']
    15031645
     1646Custom error messages
     1647>>> e = {'required': 'REQUIRED'}
     1648>>> e['invalid'] = 'INVALID'
     1649>>> e['min_length'] = 'LENGTH %(length)s, MIN LENGTH %(min)s'
     1650>>> e['max_length'] = 'LENGTH %(length)s, MAX LENGTH %(max)s'
     1651>>> f = RegexField(r'^\d+$', min_length=5, max_length=10, error_messages=e)
     1652>>> f.clean('')
     1653Traceback (most recent call last):
     1654...
     1655ValidationError: [u'REQUIRED']
     1656>>> f.clean('abcde')
     1657Traceback (most recent call last):
     1658...
     1659ValidationError: [u'INVALID']
     1660>>> f.clean('1234')
     1661Traceback (most recent call last):
     1662...
     1663ValidationError: [u'LENGTH 4, MIN LENGTH 5']
     1664>>> f.clean('12345678901')
     1665Traceback (most recent call last):
     1666...
     1667ValidationError: [u'LENGTH 11, MAX LENGTH 10']
     1668
    15041669# EmailField ##################################################################
    15051670
    15061671>>> f = EmailField()
     
    15601725...
    15611726ValidationError: [u'Ensure this value has at most 15 characters (it has 20).']
    15621727
     1728Custom error messages
     1729>>> e = {'required': 'REQUIRED'}
     1730>>> e['invalid'] = 'INVALID'
     1731>>> e['min_length'] = 'LENGTH %(length)s, MIN LENGTH %(min)s'
     1732>>> e['max_length'] = 'LENGTH %(length)s, MAX LENGTH %(max)s'
     1733>>> f = EmailField(min_length=8, max_length=10, error_messages=e)
     1734>>> f.clean('')
     1735Traceback (most recent call last):
     1736...
     1737ValidationError: [u'REQUIRED']
     1738>>> f.clean('abcdefgh')
     1739Traceback (most recent call last):
     1740...
     1741ValidationError: [u'INVALID']
     1742>>> f.clean('a@b.com')
     1743Traceback (most recent call last):
     1744...
     1745ValidationError: [u'LENGTH 7, MIN LENGTH 8']
     1746>>> f.clean('aye@bee.com')
     1747Traceback (most recent call last):
     1748...
     1749ValidationError: [u'LENGTH 11, MAX LENGTH 10']
     1750
    15631751# FileField ##################################################################
    15641752
    15651753>>> f = FileField()
     
    15961784>>> type(f.clean({'filename': 'name', 'content':'Some File Content'}))
    15971785<class 'django.newforms.fields.UploadedFile'>
    15981786
     1787Custom error messages
     1788>>> e = {'required': 'REQUIRED'}
     1789>>> e['invalid'] = 'INVALID'
     1790>>> e['missing'] = 'MISSING'
     1791>>> e['empty'] = 'EMPTY FILE'
     1792>>> f = FileField(error_messages=e)
     1793>>> f.clean('')
     1794Traceback (most recent call last):
     1795...
     1796ValidationError: [u'REQUIRED']
     1797>>> f.clean('abc')
     1798Traceback (most recent call last):
     1799...
     1800ValidationError: [u'INVALID']
     1801>>> f.clean({})
     1802Traceback (most recent call last):
     1803...
     1804ValidationError: [u'MISSING']
     1805>>> f.clean({'filename': 'name', 'content':''})
     1806Traceback (most recent call last):
     1807...
     1808ValidationError: [u'EMPTY FILE']
     1809
    15991810# URLField ##################################################################
    16001811
    16011812>>> f = URLField()
     
    17151926>>> f.clean('https://example.com')
    17161927u'https://example.com'
    17171928
     1929Custom error messages
     1930>>> e = {'required': 'REQUIRED'}
     1931>>> e['invalid'] = 'INVALID'
     1932>>> e['invalid_link'] = 'INVALID LINK'
     1933>>> f = URLField(verify_exists=True, error_messages=e)
     1934>>> f.clean('')
     1935Traceback (most recent call last):
     1936...
     1937ValidationError: [u'REQUIRED']
     1938>>> f.clean('abc.c')
     1939Traceback (most recent call last):
     1940...
     1941ValidationError: [u'INVALID']
     1942>>> f.clean('http://www.jfoiwjfoi23jfoijoaijfoiwjofiwjefewl.com')
     1943Traceback (most recent call last):
     1944...
     1945ValidationError: [u'INVALID LINK']
     1946
    17181947# BooleanField ################################################################
    17191948
    17201949>>> f = BooleanField()
     
    17531982>>> f.clean('Django rocks')
    17541983True
    17551984
     1985Custom error messages
     1986>>> e = {'required': 'REQUIRED'}
     1987>>> f = BooleanField(error_messages=e)
     1988>>> f.clean('')
     1989Traceback (most recent call last):
     1990...
     1991ValidationError: [u'REQUIRED']
     1992
    17561993# ChoiceField #################################################################
    17571994
    17581995>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')])
     
    17952032...
    17962033ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
    17972034
     2035Custom error messages
     2036>>> e = {'required': 'REQUIRED'}
     2037>>> e['invalid_choice'] = '%(value)s IS INVALID CHOICE'
     2038>>> f = ChoiceField(choices=[('a', 'aye')], error_messages=e)
     2039>>> f.clean('')
     2040Traceback (most recent call last):
     2041...
     2042ValidationError: [u'REQUIRED']
     2043>>> f.clean('b')
     2044Traceback (most recent call last):
     2045...
     2046ValidationError: [u'b IS INVALID CHOICE']
     2047
    17982048# NullBooleanField ############################################################
    17992049
    18002050>>> f = NullBooleanField()
     
    18752125...
    18762126ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
    18772127
     2128Custom error messages
     2129>>> e = {'required': 'REQUIRED'}
     2130>>> e['invalid_choice'] = '%(value)s IS INVALID CHOICE'
     2131>>> e['invalid_list'] = 'NOT A LIST'
     2132>>> f = MultipleChoiceField(choices=[('a', 'aye')], error_messages=e)
     2133>>> f.clean('')
     2134Traceback (most recent call last):
     2135...
     2136ValidationError: [u'REQUIRED']
     2137>>> f.clean('b')
     2138Traceback (most recent call last):
     2139...
     2140ValidationError: [u'NOT A LIST']
     2141>>> f.clean(['b'])
     2142Traceback (most recent call last):
     2143...
     2144ValidationError: [u'b IS INVALID CHOICE']
     2145
    18782146# ComboField ##################################################################
    18792147
    18802148ComboField takes a list of fields that should be used to validate a value,
     
    19832251...
    19842252ValidationError: [u'Enter a valid date.']
    19852253
     2254Custom error messages
     2255>>> e = {'required': 'REQUIRED'}
     2256>>> e['invalid_date'] = 'INVALID DATE'
     2257>>> e['invalid_time'] = 'INVALID TIME'
     2258>>> f = SplitDateTimeField(error_messages=e)
     2259>>> f.clean('')
     2260Traceback (most recent call last):
     2261...
     2262ValidationError: [u'REQUIRED']
     2263>>> f.clean(['a', 'b'])
     2264Traceback (most recent call last):
     2265...
     2266ValidationError: [u'INVALID DATE', u'INVALID TIME']
     2267
    19862268#########
    19872269# Forms #
    19882270#########
  • docs/newforms.txt

     
    10201020    <p>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</p>
    10211021    <p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
    10221022
     1023``error_messages``
     1024~~~~~~~~~~~~~~~~~~
     1025
     1026The ``error_messages`` argument lets you override the default messages which the
     1027field will raise. Pass in a dictionary with keys matching the error messages you
     1028want to override. For example::
     1029
     1030    >>> generic = forms.CharField()
     1031    >>> generic.clean('')
     1032    Traceback (most recent call last):
     1033      ...
     1034    ValidationError: [u'This field is required.']
     1035
     1036    >>> name = forms.CharField(error_messages={'required': 'Please enter your name'})
     1037    >>> name.clean('')
     1038    Traceback (most recent call last):
     1039      ...
     1040    ValidationError: [u'Please enter your name']
     1041
     1042In the `built-in Field classes`_ section below, each Field defines the error
     1043message keys it uses. 
     1044
    10231045Dynamic initial values
    10241046----------------------
    10251047
     
    10841106    * Empty value: ``None``
    10851107    * Normalizes to: A Python ``True`` or ``False`` value.
    10861108    * Validates nothing (i.e., it never raises a ``ValidationError``).
     1109    * Error message keys: ``required``
    10871110
    10881111``CharField``
    10891112~~~~~~~~~~~~~
     
    10921115    * Empty value: ``''`` (an empty string)
    10931116    * Normalizes to: A Unicode object.
    10941117    * Validates nothing, unless ``max_length`` or ``min_length`` is provided.
     1118    * Error message keys: ``required``, ``max_length``, ``min_length``
    10951119
    10961120Has two optional arguments for validation, ``max_length`` and ``min_length``.
    10971121If provided, these arguments ensure that the string is at most or at least the
     
    11041128    * Empty value: ``''`` (an empty string)
    11051129    * Normalizes to: A Unicode object.
    11061130    * Validates that the given value exists in the list of choices.
     1131    * Error message keys: ``required``, ``invalid_choice``
    11071132
    11081133Takes one extra argument, ``choices``, which is an iterable (e.g., a list or
    11091134tuple) of 2-tuples to use as choices for this field.
     
    11161141    * Normalizes to: A Python ``datetime.date`` object.
    11171142    * Validates that the given value is either a ``datetime.date``,
    11181143      ``datetime.datetime`` or string formatted in a particular date format.
     1144    * Error message keys: ``required``, ``invalid``
    11191145
    11201146Takes one optional argument, ``input_formats``, which is a list of formats used
    11211147to attempt to convert a string to a valid ``datetime.date`` object.
     
    11361162    * Normalizes to: A Python ``datetime.datetime`` object.
    11371163    * Validates that the given value is either a ``datetime.datetime``,
    11381164      ``datetime.date`` or string formatted in a particular datetime format.
     1165    * Error message keys: ``required``, ``invalid``
    11391166
    11401167Takes one optional argument, ``input_formats``, which is a list of formats used
    11411168to attempt to convert a string to a valid ``datetime.datetime`` object.
     
    11621189    * Normalizes to: A Python ``decimal``.
    11631190    * Validates that the given value is a decimal. Leading and trailing
    11641191      whitespace is ignored.
     1192    * Error message keys: ``required``, ``invalid``, ``max_value``,
     1193      ``min_value``, ``max_digits``, ``max_decimal_places``,
     1194      ``max_whole_digits``
    11651195
    11661196Takes four optional arguments: ``max_value``, ``min_value``, ``max_digits``,
    11671197and ``decimal_places``. The first two define the limits for the fields value.
     
    11781208    * Normalizes to: A Unicode object.
    11791209    * Validates that the given value is a valid e-mail address, using a
    11801210      moderately complex regular expression.
     1211    * Error message keys: ``required``, ``invalid``
    11811212
    11821213Has two optional arguments for validation, ``max_length`` and ``min_length``.
    11831214If provided, these arguments ensure that the string is at most or at least the
     
    11931224    * Normalizes to: An ``UploadedFile`` object that wraps the file content
    11941225      and file name into a single object.
    11951226    * Validates that non-empty file data has been bound to the form.
     1227    * Error message keys: ``required``, ``invalid``, ``missing``, ``empty``
    11961228
    11971229An ``UploadedFile`` object has two attributes:
    11981230
     
    12231255      and file name into a single object.
    12241256    * Validates that file data has been bound to the form, and that the
    12251257      file is of an image format understood by PIL.
     1258    * Error message keys: ``required``, ``invalid``, ``missing``, ``empty``,
     1259      ``invalid_image``
    12261260
    12271261Using an ImageField requires that the `Python Imaging Library`_ is installed.
    12281262
     
    12391273    * Normalizes to: A Python integer or long integer.
    12401274    * Validates that the given value is an integer. Leading and trailing
    12411275      whitespace is allowed, as in Python's ``int()`` function.
     1276    * Error message keys: ``required``, ``invalid``, ``max_value``,
     1277      ``min_value``
    12421278
    12431279Takes two optional arguments for validation, ``max_value`` and ``min_value``.
    12441280These control the range of values permitted in the field.
     
    12511287    * Normalizes to: A list of Unicode objects.
    12521288    * Validates that every value in the given list of values exists in the list
    12531289      of choices.
     1290    * Error message keys: ``required``, ``invalid_choice``, ``invalid_list``
    12541291
    12551292Takes one extra argument, ``choices``, which is an iterable (e.g., a list or
    12561293tuple) of 2-tuples to use as choices for this field.
     
    12711308    * Normalizes to: A Unicode object.
    12721309    * Validates that the given value matches against a certain regular
    12731310      expression.
     1311    * Error message keys: ``required``, ``invalid``
    12741312
    12751313Takes one required argument, ``regex``, which is a regular expression specified
    12761314either as a string or a compiled regular expression object.
     
    12821320    ======================  =====================================================
    12831321    ``max_length``          Ensures the string has at most this many characters.
    12841322    ``min_length``          Ensures the string has at least this many characters.
    1285     ``error_message``       Error message to return for failed validation. If no
    1286                             message is provided, a generic error message will be
    1287                             used.
    12881323    ======================  =====================================================
    12891324
     1325The optional argument ``error_message`` is also accepted for backwards
     1326compatibility. The preferred way to provide an error message is to use the
     1327``error_messages`` argument, passing a dictionary with ``'invalid'`` as a key
     1328and the error message as the value.
     1329
    12901330``TimeField``
    12911331~~~~~~~~~~~~~
    12921332
     
    12951335    * Normalizes to: A Python ``datetime.time`` object.
    12961336    * Validates that the given value is either a ``datetime.time`` or string
    12971337      formatted in a particular time format.
     1338    * Error message keys: ``required``, ``invalid``
    12981339
    12991340Takes one optional argument, ``input_formats``, which is a list of formats used
    13001341to attempt to convert a string to a valid ``datetime.time`` object.
     
    13111352    * Empty value: ``''`` (an empty string)
    13121353    * Normalizes to: A Unicode object.
    13131354    * Validates that the given value is a valid URL.
     1355    * Error message keys: ``required``, ``invalid``, ``invalid_link``
    13141356
    13151357Takes the following optional arguments:
    13161358
Back to Top