Ticket #3457: newforms_error_messages.2.patch
File newforms_error_messages.2.patch, 22.8 KB (added by , 17 years ago) |
---|
-
django/newforms/fields.py
6 6 import re 7 7 import time 8 8 9 from django.utils.translation import ugettext 9 from django.utils.translation import ugettext_lazy 10 10 from django.utils.encoding import StrAndUnicode, smart_unicode 11 11 12 12 from util import ErrorList, ValidationError … … 44 44 class Field(object): 45 45 widget = TextInput # Default widget to use when rendering this type of Field. 46 46 hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden". 47 default_error_messages = { 48 'required': ugettext_lazy(u'This field is required.'), 49 'invalid': ugettext_lazy(u'Enter a valid value.'), 50 } 47 51 48 52 # Tracks each time a Field instance is created. Used to retain order. 49 53 creation_counter = 0 50 54 51 def __init__(self, required=True, widget=None, label=None, initial=None, help_text=None): 55 def __init__(self, required=True, widget=None, label=None, initial=None, 56 help_text=None, error_messages=None): 52 57 # required -- Boolean that specifies whether the field is required. 53 58 # True by default. 54 59 # widget -- A Widget class, or instance of a Widget class, that should … … 81 86 self.creation_counter = Field.creation_counter 82 87 Field.creation_counter += 1 83 88 89 self.error_messages = self._build_error_messages(error_messages) 90 91 def _build_error_messages(self, extra_error_messages): 92 error_messages = {} 93 def get_default_error_messages(klass): 94 for base_class in klass.__bases__: 95 get_default_error_messages(base_class) 96 if hasattr(klass, 'default_error_messages'): 97 error_messages.update(klass.default_error_messages) 98 get_default_error_messages(self.__class__) 99 if extra_error_messages: 100 error_messages.update(extra_error_messages) 101 return error_messages 102 84 103 def clean(self, value): 85 104 """ 86 105 Validates the given value and returns its "cleaned" value as an … … 89 108 Raises ValidationError for any errors. 90 109 """ 91 110 if self.required and value in EMPTY_VALUES: 92 raise ValidationError( ugettext(u'This field is required.'))111 raise ValidationError(self.error_messages['required']) 93 112 return value 94 113 95 114 def widget_attrs(self, widget): … … 101 120 return {} 102 121 103 122 class CharField(Field): 123 default_error_messages = { 124 'max_length': ugettext_lazy(u'Ensure this value has at most %(max)d characters (it has %(length)d).'), 125 'min_length': ugettext_lazy(u'Ensure this value has at least %(min)d characters (it has %(length)d).'), 126 } 127 104 128 def __init__(self, max_length=None, min_length=None, *args, **kwargs): 105 129 self.max_length, self.min_length = max_length, min_length 106 130 super(CharField, self).__init__(*args, **kwargs) … … 113 137 value = smart_unicode(value) 114 138 value_length = len(value) 115 139 if self.max_length is not None and value_length > self.max_length: 116 raise ValidationError( ugettext(u'Ensure this value has at most %(max)d characters (it has %(length)d).')% {'max': self.max_length, 'length': value_length})140 raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length}) 117 141 if self.min_length is not None and value_length < self.min_length: 118 raise ValidationError( ugettext(u'Ensure this value has at least %(min)d characters (it has %(length)d).')% {'min': self.min_length, 'length': value_length})142 raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length}) 119 143 return value 120 144 121 145 def widget_attrs(self, widget): … … 124 148 return {'maxlength': str(self.max_length)} 125 149 126 150 class IntegerField(Field): 151 default_error_messages = { 152 'invalid': ugettext_lazy(u'Enter a whole number.'), 153 'max_value': ugettext_lazy(u'Ensure this value is less than or equal to %s.'), 154 'min_value': ugettext_lazy(u'Ensure this value is greater than or equal to %s.'), 155 } 156 127 157 def __init__(self, max_value=None, min_value=None, *args, **kwargs): 128 158 self.max_value, self.min_value = max_value, min_value 129 159 super(IntegerField, self).__init__(*args, **kwargs) … … 139 169 try: 140 170 value = int(value) 141 171 except (ValueError, TypeError): 142 raise ValidationError( ugettext(u'Enter a whole number.'))172 raise ValidationError(self.error_messages['invalid']) 143 173 if self.max_value is not None and value > self.max_value: 144 raise ValidationError( ugettext(u'Ensure this value is less than or equal to %s.')% self.max_value)174 raise ValidationError(self.error_messages['max_value'] % self.max_value) 145 175 if self.min_value is not None and value < self.min_value: 146 raise ValidationError( ugettext(u'Ensure this value is greater than or equal to %s.')% self.min_value)176 raise ValidationError(self.error_messages['min_value'] % self.min_value) 147 177 return value 148 178 149 179 class FloatField(Field): 180 default_error_messages = { 181 'invalid': ugettext_lazy(u'Enter a number.'), 182 'max_value': ugettext_lazy(u'Ensure this value is less than or equal to %s.'), 183 'min_value': ugettext_lazy(u'Ensure this value is greater than or equal to %s.'), 184 } 185 150 186 def __init__(self, max_value=None, min_value=None, *args, **kwargs): 151 187 self.max_value, self.min_value = max_value, min_value 152 188 Field.__init__(self, *args, **kwargs) … … 162 198 try: 163 199 value = float(value) 164 200 except (ValueError, TypeError): 165 raise ValidationError( ugettext('Enter a number.'))201 raise ValidationError(self.error_messages['invalid']) 166 202 if self.max_value is not None and value > self.max_value: 167 raise ValidationError( ugettext('Ensure this value is less than or equal to %s.')% self.max_value)203 raise ValidationError(self.error_messages['max_value'] % self.max_value) 168 204 if self.min_value is not None and value < self.min_value: 169 raise ValidationError( ugettext('Ensure this value is greater than or equal to %s.')% self.min_value)205 raise ValidationError(self.error_messages['min_value'] % self.min_value) 170 206 return value 171 207 172 208 class DecimalField(Field): 209 default_error_messages = { 210 'invalid': ugettext_lazy(u'Enter a number.'), 211 'max_value': ugettext_lazy(u'Ensure this value is less than or equal to %s.'), 212 'min_value': ugettext_lazy(u'Ensure this value is greater than or equal to %s.'), 213 'max_digits': ugettext_lazy('Ensure that there are no more than %s digits in total.'), 214 'max_decimal_places': ugettext_lazy('Ensure that there are no more than %s decimal places.'), 215 'max_whole_digits': ugettext_lazy('Ensure that there are no more than %s digits before the decimal point.') 216 } 217 173 218 def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs): 174 219 self.max_value, self.min_value = max_value, min_value 175 220 self.max_digits, self.decimal_places = max_digits, decimal_places … … 189 234 try: 190 235 value = Decimal(value) 191 236 except DecimalException: 192 raise ValidationError( ugettext('Enter a number.'))237 raise ValidationError(self.error_messages['invalid']) 193 238 pieces = str(value).lstrip("-").split('.') 194 239 decimals = (len(pieces) == 2) and len(pieces[1]) or 0 195 240 digits = len(pieces[0]) 196 241 if self.max_value is not None and value > self.max_value: 197 raise ValidationError( ugettext('Ensure this value is less than or equal to %s.')% self.max_value)242 raise ValidationError(self.error_messages['max_value'] % self.max_value) 198 243 if self.min_value is not None and value < self.min_value: 199 raise ValidationError( ugettext('Ensure this value is greater than or equal to %s.')% self.min_value)244 raise ValidationError(self.error_messages['min_value'] % self.min_value) 200 245 if self.max_digits is not None and (digits + decimals) > self.max_digits: 201 raise ValidationError( ugettext('Ensure that there are no more than %s digits in total.')% self.max_digits)246 raise ValidationError(self.error_messages['max_digits'] % self.max_digits) 202 247 if self.decimal_places is not None and decimals > self.decimal_places: 203 raise ValidationError( ugettext('Ensure that there are no more than %s decimal places.')% self.decimal_places)248 raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places) 204 249 if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places): 205 raise ValidationError( ugettext('Ensure that there are no more than %s digits before the decimal point.')% (self.max_digits - self.decimal_places))250 raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) 206 251 return value 207 252 208 253 DEFAULT_DATE_INPUT_FORMATS = ( … … 214 259 ) 215 260 216 261 class DateField(Field): 262 default_error_messages = { 263 'invalid': ugettext_lazy(u'Enter a valid date.'), 264 } 265 217 266 def __init__(self, input_formats=None, *args, **kwargs): 218 267 super(DateField, self).__init__(*args, **kwargs) 219 268 self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS … … 235 284 return datetime.date(*time.strptime(value, format)[:3]) 236 285 except ValueError: 237 286 continue 238 raise ValidationError( ugettext(u'Enter a valid date.'))287 raise ValidationError(self.error_messages['invalid']) 239 288 240 289 DEFAULT_TIME_INPUT_FORMATS = ( 241 290 '%H:%M:%S', # '14:30:59' … … 243 292 ) 244 293 245 294 class TimeField(Field): 295 default_error_messages = { 296 'invalid': ugettext_lazy(u'Enter a valid time.') 297 } 298 246 299 def __init__(self, input_formats=None, *args, **kwargs): 247 300 super(TimeField, self).__init__(*args, **kwargs) 248 301 self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS … … 262 315 return datetime.time(*time.strptime(value, format)[3:6]) 263 316 except ValueError: 264 317 continue 265 raise ValidationError( ugettext(u'Enter a valid time.'))318 raise ValidationError(self.error_messages['invalid']) 266 319 267 320 DEFAULT_DATETIME_INPUT_FORMATS = ( 268 321 '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' … … 277 330 ) 278 331 279 332 class DateTimeField(Field): 333 default_error_messages = { 334 'invalid': ugettext_lazy(u'Enter a valid date/time.'), 335 } 336 280 337 def __init__(self, input_formats=None, *args, **kwargs): 281 338 super(DateTimeField, self).__init__(*args, **kwargs) 282 339 self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS … … 298 355 return datetime.datetime(*time.strptime(value, format)[:6]) 299 356 except ValueError: 300 357 continue 301 raise ValidationError( ugettext(u'Enter a valid date/time.'))358 raise ValidationError(self.error_messages['invalid']) 302 359 303 360 class RegexField(CharField): 304 361 def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs): … … 307 364 error_message is an optional error message to use, if 308 365 'Enter a valid value' is too generic for you. 309 366 """ 367 # error_message is just kept for backwards compatibility: 368 if error_message: 369 error_messages = kwargs.get('error_messages') or {} 370 error_messages['invalid'] = error_message 371 kwargs['error_messages'] = error_messages 310 372 super(RegexField, self).__init__(max_length, min_length, *args, **kwargs) 311 373 if isinstance(regex, basestring): 312 374 regex = re.compile(regex) 313 375 self.regex = regex 314 self.error_message = error_message or ugettext(u'Enter a valid value.')315 376 316 377 def clean(self, value): 317 378 """ … … 322 383 if value == u'': 323 384 return value 324 385 if not self.regex.search(value): 325 raise ValidationError(self.error_message )386 raise ValidationError(self.error_messages['invalid']) 326 387 return value 327 388 328 389 email_re = re.compile( … … 331 392 r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain 332 393 333 394 class EmailField(RegexField): 395 default_error_messages = { 396 'invalid': ugettext_lazy(u'Enter a valid e-mail address.'), 397 } 398 334 399 def __init__(self, max_length=None, min_length=None, *args, **kwargs): 335 RegexField.__init__(self, email_re, max_length, min_length, 336 ugettext(u'Enter a valid e-mail address.'), *args,**kwargs)400 RegexField.__init__(self, email_re, max_length, min_length, *args, 401 **kwargs) 337 402 338 403 url_re = re.compile( 339 404 r'^https?://' # http:// or https:// … … 363 428 364 429 class FileField(Field): 365 430 widget = FileInput 431 default_error_messages = { 432 'invalid': ugettext_lazy(u"No file was submitted. Check the encoding type on the form."), 433 'missing': ugettext_lazy(u"No file was submitted."), 434 'empty': ugettext_lazy(u"The submitted file is empty."), 435 } 436 366 437 def __init__(self, *args, **kwargs): 367 438 super(FileField, self).__init__(*args, **kwargs) 368 439 … … 373 444 try: 374 445 f = UploadedFile(data['filename'], data['content']) 375 446 except TypeError: 376 raise ValidationError( ugettext(u"No file was submitted. Check the encoding type on the form."))447 raise ValidationError(self.error_messages['invalid']) 377 448 except KeyError: 378 raise ValidationError( ugettext(u"No file was submitted."))449 raise ValidationError(self.error_messages['missing']) 379 450 if not f.content: 380 raise ValidationError( ugettext(u"The submitted file is empty."))451 raise ValidationError(self.error_messages['empty']) 381 452 return f 382 453 383 454 class ImageField(FileField): 455 default_error_messages = { 456 'invalid_image': ugettext_lazy(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."), 457 } 458 384 459 def clean(self, data): 385 460 """ 386 461 Checks that the file-upload field data contains a valid image (GIF, JPG, … … 394 469 try: 395 470 Image.open(StringIO(f.content)) 396 471 except IOError: # Python Imaging Library doesn't recognize it as an image 397 raise ValidationError( ugettext(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."))472 raise ValidationError(self.error_messages['invalid_image']) 398 473 return f 399 474 400 475 class URLField(RegexField): 476 default_error_messages = { 477 'invalid': ugettext_lazy(u'Enter a valid URL.'), 478 'invalid_link': ugettext_lazy(u'This URL appears to be a broken link.'), 479 } 480 401 481 def __init__(self, max_length=None, min_length=None, verify_exists=False, 402 482 validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs): 403 super(URLField, self).__init__(url_re, max_length, min_length, ugettext (u'Enter a valid URL.'), *args, **kwargs)483 super(URLField, self).__init__(url_re, max_length, min_length, ugettext_lazy(u'Enter a valid URL.'), *args, **kwargs) 404 484 self.verify_exists = verify_exists 405 485 self.user_agent = validator_user_agent 406 486 … … 422 502 req = urllib2.Request(value, None, headers) 423 503 u = urllib2.urlopen(req) 424 504 except ValueError: 425 raise ValidationError( ugettext(u'Enter a valid URL.'))505 raise ValidationError(self.error_messages['invalid']) 426 506 except: # urllib2.URLError, httplib.InvalidURL, etc. 427 raise ValidationError( ugettext(u'This URL appears to be a broken link.'))507 raise ValidationError(self.error_messages['invalid_link']) 428 508 return value 429 509 430 510 class BooleanField(Field): … … 447 527 448 528 class ChoiceField(Field): 449 529 widget = Select 530 default_error_messages = { 531 'invalid_choice': ugettext_lazy(u'Select a valid choice. That choice is not one of the available choices.'), 532 } 450 533 451 def __init__(self, choices=(), required=True, widget=None, label=None, initial=None, help_text=None): 452 super(ChoiceField, self).__init__(required, widget, label, initial, help_text) 534 def __init__(self, choices=(), required=True, widget=None, label=None, 535 initial=None, help_text=None, *args, **kwargs): 536 super(ChoiceField, self).__init__(required, widget, label, initial, 537 help_text, *args, **kwargs) 453 538 self.choices = choices 454 539 455 540 def _get_choices(self): … … 475 560 return value 476 561 valid_values = set([smart_unicode(k) for k, v in self.choices]) 477 562 if value not in valid_values: 478 raise ValidationError( ugettext(u'Select a valid choice. That choice is not one of the available choices.'))563 raise ValidationError(self.error_messages['invalid_choice'] % {'value': value}) 479 564 return value 480 565 481 566 class MultipleChoiceField(ChoiceField): 482 567 hidden_widget = MultipleHiddenInput 483 568 widget = SelectMultiple 569 default_error_messages = { 570 'invalid_choice': ugettext_lazy(u'Select a valid choice. %(value)s is not one of the available choices.') 571 } 484 572 485 573 def clean(self, value): 486 574 """ 487 575 Validates that the input is a list or tuple. 488 576 """ 489 577 if self.required and not value: 490 raise ValidationError(ugettext (u'This field is required.'))578 raise ValidationError(ugettext_lazy(u'This field is required.')) 491 579 elif not self.required and not value: 492 580 return [] 493 581 if not isinstance(value, (list, tuple)): 494 raise ValidationError(ugettext (u'Enter a list of values.'))582 raise ValidationError(ugettext_lazy(u'Enter a list of values.')) 495 583 new_value = [smart_unicode(val) for val in value] 496 584 # Validate that each value in the value list is in self.choices. 497 585 valid_values = set([smart_unicode(k) for k, v in self.choices]) 498 586 for val in new_value: 499 587 if val not in valid_values: 500 raise ValidationError( ugettext(u'Select a valid choice. %s is not one of the available choices.') % val)588 raise ValidationError(self.error_messages['invalid_choice'] % {'value': val}) 501 589 return new_value 502 590 503 591 class ComboField(Field): … … 540 628 541 629 You'll probably want to use this with MultiWidget. 542 630 """ 631 default_error_messages = { 632 'invalid': ugettext_lazy(u'Enter a list of values.'), 633 } 543 634 def __init__(self, fields=(), *args, **kwargs): 544 635 super(MultiValueField, self).__init__(*args, **kwargs) 545 636 # Set 'required' to False on the individual fields, because the … … 563 654 if not value or isinstance(value, (list, tuple)): 564 655 if not value or not [v for v in value if v not in EMPTY_VALUES]: 565 656 if self.required: 566 raise ValidationError( ugettext(u'This field is required.'))657 raise ValidationError(self.error_messages['required']) 567 658 else: 568 659 return self.compress([]) 569 660 else: 570 raise ValidationError( ugettext(u'Enter a list of values.'))661 raise ValidationError(self.error_messages['invalid']) 571 662 for i, field in enumerate(self.fields): 572 663 try: 573 664 field_value = value[i] 574 665 except IndexError: 575 666 field_value = None 576 667 if self.required and field_value in EMPTY_VALUES: 577 raise ValidationError( ugettext(u'This field is required.'))668 raise ValidationError(self.error_messages['required']) 578 669 try: 579 670 clean_data.append(field.clean(field_value)) 580 671 except ValidationError, e: … … 598 689 raise NotImplementedError('Subclasses must implement this method.') 599 690 600 691 class SplitDateTimeField(MultiValueField): 692 default_error_messages = { 693 'invalid_date': ugettext_lazy(u'Enter a valid date.'), 694 'invalid_time': ugettext_lazy(u'Enter a valid time.'), 695 } 601 696 def __init__(self, *args, **kwargs): 602 697 fields = (DateField(), TimeField()) 603 698 super(SplitDateTimeField, self).__init__(fields, *args, **kwargs) … … 607 702 # Raise a validation error if time or date is empty 608 703 # (possible if SplitDateTimeField has required=False). 609 704 if data_list[0] in EMPTY_VALUES: 610 raise ValidationError( ugettext(u'Enter a valid date.'))705 raise ValidationError(self.error_messages['invalid_date']) 611 706 if data_list[1] in EMPTY_VALUES: 612 raise ValidationError( ugettext(u'Enter a valid time.'))707 raise ValidationError(self.error_messages['invalid_time']) 613 708 return datetime.datetime.combine(*data_list) 614 709 return None -
django/newforms/util.py
1 1 from django.utils.html import escape 2 from django.utils.encoding import smart_unicode, StrAndUnicode2 from django.utils.encoding import smart_unicode, force_unicode, StrAndUnicode 3 3 4 4 def flatatt(attrs): 5 5 """ … … 41 41 if not self: return u'' 42 42 return u'\n'.join([u'* %s' % smart_unicode(e) for e in self]) 43 43 44 def __repr__(self): 45 return repr([force_unicode(e) for e in self]) 46 44 47 class ValidationError(Exception): 45 48 def __init__(self, message): 46 49 "ValidationError can be passed a string or a list." 47 50 if isinstance(message, list): 48 51 self.messages = ErrorList([smart_unicode(msg) for msg in message]) 49 52 else: 50 assert isinstance(message, basestring), ("%s should be a basestring" % repr(message))51 53 message = smart_unicode(message) 52 54 self.messages = ErrorList([message]) 53 55 -
django/utils/translation/__init__.py
8 8 'get_language', 'get_language_bidi', 'get_date_formats', 9 9 'get_partial_date_formats', 'check_for_language', 'to_locale', 10 10 'get_language_from_request', 'install', 'templatize', 'ugettext', 11 'u ngettext', 'deactivate_all']11 'ugettext_lazy', 'ungettext', 'deactivate_all'] 12 12 13 13 # Here be dragons, so a short explanation of the logic won't hurt: 14 14 # We are trying to solve two problems: (1) access settings, in particular