Django

Code

Ticket #3457: newforms_error_messages.4.patch

File newforms_error_messages.4.patch, 42.7 kB (added by gwilson, 1 year ago)
  • django/test/testcases.py

    old new  
    88from django.core.management import call_command 
    99from django.test import _doctest as doctest 
    1010from django.test.client import Client 
     11from django.utils.encoding import force_unicode 
    1112 
    1213normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s) 
    1314 
     
    140141            for err in errors: 
    141142                if field: 
    142143                    if field in context[form].errors: 
     144                        #field_errors = [force_unicode(error) for error 
     145                        #                in context[form].errors[field]] 
    143146                        field_errors = context[form].errors[field] 
    144147                        self.failUnless(err in field_errors, 
    145                                         "The field '%s' on form '%s' in" 
    146                                         " context %d does not contain the" 
    147                                         " error '%s' (actual errors: %s)" % 
     148                                        u"The field '%s' on form '%s' in" 
     149                                        u" context %d does not contain the" 
     150                                        u" error '%s' (actual errors: %s)" % 
    148151                                            (field, form, i, err, 
    149152                                             list(field_errors))) 
    150153                    elif field in context[form].fields: 
  • django/newforms/util.py

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

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

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

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

    old new  
    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``).