Ticket #6845: 6845-against-django-7338.diff
File 6845-against-django-7338.diff, 133.7 KB (added by , 17 years ago) |
---|
-
AUTHORS
diff --git a/AUTHORS b/AUTHORS index 2329c8b..fed146e 100644
a b answer newbie questions, and generally made Django that much better: 379 379 ymasuda@ethercube.com 380 380 Jarek Zgoda <jarek.zgoda@gmail.com> 381 381 Cheng Zhang 382 Honza Kral <Honza.Kral@gmail.com> 382 383 383 384 A big THANK YOU goes to: 384 385 -
django/contrib/admin/views/template.py
diff --git a/django/contrib/admin/views/template.py b/django/contrib/admin/views/template.py index a3b4538..89e6952 100644
a b 1 1 from django.contrib.admin.views.decorators import staff_member_required 2 from django.core import validat ors2 from django.core import validation 3 3 from django import template, oldforms 4 4 from django.template import loader 5 5 from django.shortcuts import render_to_response … … class TemplateValidator(oldforms.Manipulator): 69 69 error = e 70 70 template.builtins.remove(register) 71 71 if error: 72 raise validat ors.ValidationError, e.args72 raise validation.ValidationError, e.args -
django/contrib/auth/create_superuser.py
diff --git a/django/contrib/auth/create_superuser.py b/django/contrib/auth/create_superuser.py index 7b6cefd..0d08ff1 100644
a b def createsuperuser(username=None, email=None, password=None): 61 61 if not email: 62 62 email = raw_input('E-mail address: ') 63 63 try: 64 validators. isValidEmail(email, None)64 validators.validate_email(email) 65 65 except validators.ValidationError: 66 66 sys.stderr.write("Error: That e-mail address is invalid.\n") 67 67 email = None -
django/contrib/auth/forms.py
diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index 47a974c..b1af278 100644
a b from django.contrib.auth.models import User 2 2 from django.contrib.auth import authenticate 3 3 from django.contrib.sites.models import Site 4 4 from django.template import Context, loader 5 from django. coreimport validators5 from django.oldforms import validators 6 6 from django import oldforms 7 7 from django.utils.translation import ugettext as _ 8 8 -
django/contrib/auth/models.py
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index 4b15902..aa2eb5e 100644
a b 1 1 from django.contrib import auth 2 from django. coreimport validators2 from django.oldforms import validators 3 3 from django.core.exceptions import ImproperlyConfigured 4 4 from django.db import models 5 5 from django.db.models.manager import EmptyManager … … class User(models.Model): 128 128 129 129 Username and password are required. Other fields are optional. 130 130 """ 131 username = models.CharField(_('username'), max_length=30, unique=True, validator _list=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."))131 username = models.CharField(_('username'), max_length=30, unique=True, validators=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores).")) 132 132 first_name = models.CharField(_('first name'), max_length=30, blank=True) 133 133 last_name = models.CharField(_('last name'), max_length=30, blank=True) 134 134 email = models.EmailField(_('e-mail address'), blank=True) -
django/contrib/comments/views/comments.py
diff --git a/django/contrib/comments/views/comments.py b/django/contrib/comments/views/comments.py index 67da575..9c743bf 100644
a b 1 from django. coreimport validators1 from django.oldforms import validators 2 2 from django import oldforms 3 3 from django.core.mail import mail_admins, mail_managers 4 4 from django.http import Http404 -
django/contrib/flatpages/models.py
diff --git a/django/contrib/flatpages/models.py b/django/contrib/flatpages/models.py index 36327c8..ada2c5f 100644
a b 1 from django. coreimport validators1 from django.oldforms import validators 2 2 from django.db import models 3 3 from django.contrib.sites.models import Site 4 4 from django.utils.translation import ugettext_lazy as _ 5 5 6 6 class FlatPage(models.Model): 7 url = models.CharField(_('URL'), max_length=100, validator _list=[validators.isAlphaNumericURL], db_index=True,7 url = models.CharField(_('URL'), max_length=100, validators=[validators.isAlphaNumericURL], db_index=True, 8 8 help_text=_("Example: '/about/contact/'. Make sure to have leading and trailing slashes.")) 9 9 title = models.CharField(_('title'), max_length=200) 10 10 content = models.TextField(_('content')) -
django/contrib/localflavor/jp/forms.py
diff --git a/django/contrib/localflavor/jp/forms.py b/django/contrib/localflavor/jp/forms.py index d726f82..4d334aa 100644
a b 2 2 JP-specific Form helpers 3 3 """ 4 4 5 from django.core import validators6 5 from django.newforms import ValidationError 7 6 from django.utils.translation import ugettext 8 7 from django.newforms.fields import RegexField, Select -
django/core/exceptions.py
diff --git a/django/core/exceptions.py b/django/core/exceptions.py index d9fc326..06c92ac 100644
a b class MiddlewareNotUsed(Exception): 27 27 class ImproperlyConfigured(Exception): 28 28 "Django is somehow improperly configured" 29 29 pass 30 -
new file django/core/validation.py
diff --git a/django/core/validation.py b/django/core/validation.py new file mode 100644 index 0000000..8fe3822
- + 1 from django.utils.encoding import smart_unicode, StrAndUnicode, force_unicode 2 from django.utils.safestring import mark_safe 3 4 NON_FIELD_ERRORS = '__all__' 5 6 class ErrorList(list, StrAndUnicode): 7 """ 8 A collection of errors that knows how to display itself in various formats. 9 """ 10 def __unicode__(self): 11 return self.as_ul() 12 13 def as_ul(self): 14 if not self: return u'' 15 return mark_safe(u'<ul class="errorlist">%s</ul>' 16 % ''.join([u'<li>%s</li>' % force_unicode(e) for e in self])) 17 18 def as_text(self): 19 if not self: return u'' 20 return u'\n'.join([u'* %s' % force_unicode(e) for e in self]) 21 22 def __repr__(self): 23 return repr([force_unicode(e) for e in self]) 24 25 class ValidationError(Exception): 26 def __init__(self, message): 27 """ 28 ValidationError can be passed any object that can be printed (usually 29 a string) or a list of objects. 30 """ 31 if hasattr(message, '__iter__'): 32 self.messages = ErrorList([smart_unicode(msg) for msg in message]) 33 else: 34 message = smart_unicode(message) 35 self.messages = ErrorList([message]) 36 37 if isinstance(message, dict): 38 self.message_dict = message 39 40 def __str__(self): 41 # This is needed because, without a __str__(), printing an exception 42 # instance would result in this: 43 # AttributeError: ValidationError instance has no attribute 'args' 44 # See http://www.python.org/doc/current/tut/node10.html#handling 45 if hasattr(self, 'message_dict'): 46 return repr(self.message_dict) 47 return repr(self.messages) 48 49 class TypeCoersionError(ValidationError): 50 pass -
django/core/validators.py
diff --git a/django/core/validators.py b/django/core/validators.py index e728dbc..8be1f06 100644
a b validator will *always* be run, regardless of whether its associated 8 8 form field is required. 9 9 """ 10 10 11 import urllib212 11 import re 13 try: 14 from decimal import Decimal, DecimalException 15 except ImportError: 16 from django.utils._decimal import Decimal, DecimalException # Python 2.3 12 import urllib2 17 13 18 14 from django.conf import settings 19 from django.utils.translation import ugettext as _, ugettext_lazy, ungettext 20 from django.utils.functional import Promise, lazy 21 from django.utils.encoding import force_unicode, smart_str 15 from django.utils.translation import ugettext as _ 16 from django.core.validation import ValidationError 17 18 def regexp_validator(regexp, message): 19 if isinstance(regexp, basestring): 20 regexp = re.compile(regexp) 21 22 def _regexp_validator(value): 23 if not regexp.search(value): 24 raise ValidationError, _(message) 25 return _regexp_validator 22 26 23 _datere = r'\d{4}-\d{1,2}-\d{1,2}'24 _timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?'25 alnum_re = re.compile(r'^\w+$')26 alnumurl_re = re.compile(r'^[-\w/]+$')27 ansi_date_re = re.compile('^%s$' % _datere)28 ansi_time_re = re.compile('^%s$' % _timere)29 ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere))30 27 email_re = re.compile( 31 28 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom 32 29 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string 33 30 r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain 34 integer_re = re.compile(r'^-?\d+$')35 31 ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$') 36 32 phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE) 37 33 slug_re = re.compile(r'^[-\w]+$') 38 url_re = re.compile(r'^https?://\S+$')39 40 lazy_inter = lazy(lambda a,b: force_unicode(a) % b, unicode)41 42 class ValidationError(Exception):43 def __init__(self, message):44 "ValidationError can be passed a string or a list."45 if isinstance(message, list):46 self.messages = [force_unicode(msg) for msg in message]47 else:48 assert isinstance(message, (basestring, Promise)), ("%s should be a string" % repr(message))49 self.messages = [force_unicode(message)]50 51 def __str__(self):52 # This is needed because, without a __str__(), printing an exception53 # instance would result in this:54 # AttributeError: ValidationError instance has no attribute 'args'55 # See http://www.python.org/doc/current/tut/node10.html#handling56 return str(self.messages)57 58 class CriticalValidationError(Exception):59 def __init__(self, message):60 "ValidationError can be passed a string or a list."61 if isinstance(message, list):62 self.messages = [force_unicode(msg) for msg in message]63 else:64 assert isinstance(message, (basestring, Promise)), ("'%s' should be a string" % message)65 self.messages = [force_unicode(message)]66 67 def __str__(self):68 return str(self.messages)69 70 def isAlphaNumeric(field_data, all_data):71 if not alnum_re.search(field_data):72 raise ValidationError, _("This value must contain only letters, numbers and underscores.")73 74 def isAlphaNumericURL(field_data, all_data):75 if not alnumurl_re.search(field_data):76 raise ValidationError, _("This value must contain only letters, numbers, underscores, dashes or slashes.")77 78 def isSlug(field_data, all_data):79 if not slug_re.search(field_data):80 raise ValidationError, _("This value must contain only letters, numbers, underscores or hyphens.")81 82 def isLowerCase(field_data, all_data):83 if field_data.lower() != field_data:84 raise ValidationError, _("Uppercase letters are not allowed here.")85 34 86 def isUpperCase(field_data, all_data):87 if field_data.upper() != field_data:88 raise ValidationError, _("Lowercase letters are not allowed here.")89 35 90 def isCommaSeparatedIntegerList(field_data, all_data): 91 for supposed_int in field_data.split(','): 92 try: 93 int(supposed_int) 94 except ValueError: 95 raise ValidationError, _("Enter only digits separated by commas.") 36 validate_email = regexp_validator(email_re, 'Enter a valid e-mail address.') 37 validate_ip_address4 = regexp_validator(ip4_re, "Please enter a valid IP address.") 38 validate_phone_number = regexp_validator(phone_re, _('Phone numbers must be in XXX-XXX-XXXX format.') ) 39 validate_slug =regexp_validator(slug_re, "This value must contain only letters, numbers, underscores or hyphens.") 96 40 97 def isCommaSeparatedEmailList( field_data, all_data):41 def isCommaSeparatedEmailList(value): 98 42 """ 99 Checks that field_datais a string of e-mail addresses separated by commas.100 Blank field_datavalues will not throw a validation error, and whitespace43 Checks that value is a string of e-mail addresses separated by commas. 44 Blank value values will not throw a validation error, and whitespace 101 45 is allowed around the commas. 102 46 """ 103 for supposed_email in field_data.split(','):47 for supposed_email in value.split(','): 104 48 try: 105 isValidEmail(supposed_email.strip(), '')49 validate_email(supposed_email.strip()) 106 50 except ValidationError: 107 51 raise ValidationError, _("Enter valid e-mail addresses separated by commas.") 108 52 109 def isValidIPAddress4(field_data, all_data): 110 if not ip4_re.search(field_data): 111 raise ValidationError, _("Please enter a valid IP address.") 112 113 def isNotEmpty(field_data, all_data): 114 if field_data.strip() == '': 115 raise ValidationError, _("Empty values are not allowed here.") 116 117 def isOnlyDigits(field_data, all_data): 118 if not field_data.isdigit(): 119 raise ValidationError, _("Non-numeric characters aren't allowed here.") 120 121 def isNotOnlyDigits(field_data, all_data): 122 if field_data.isdigit(): 123 raise ValidationError, _("This value can't be comprised solely of digits.") 124 125 def isInteger(field_data, all_data): 126 # This differs from isOnlyDigits because this accepts the negative sign 127 if not integer_re.search(field_data): 128 raise ValidationError, _("Enter a whole number.") 129 130 def isOnlyLetters(field_data, all_data): 131 if not field_data.isalpha(): 132 raise ValidationError, _("Only alphabetical characters are allowed here.") 133 134 def _isValidDate(date_string): 135 """ 136 A helper function used by isValidANSIDate and isValidANSIDatetime to 137 check if the date is valid. The date string is assumed to already be in 138 YYYY-MM-DD format. 139 """ 140 from datetime import date 141 # Could use time.strptime here and catch errors, but datetime.date below 142 # produces much friendlier error messages. 143 year, month, day = map(int, date_string.split('-')) 144 # This check is needed because strftime is used when saving the date 145 # value to the database, and strftime requires that the year be >=1900. 146 if year < 1900: 147 raise ValidationError, _('Year must be 1900 or later.') 148 try: 149 date(year, month, day) 150 except ValueError, e: 151 msg = _('Invalid date: %s') % _(str(e)) 152 raise ValidationError, msg 153 154 def isValidANSIDate(field_data, all_data): 155 if not ansi_date_re.search(field_data): 156 raise ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 157 _isValidDate(field_data) 158 159 def isValidANSITime(field_data, all_data): 160 if not ansi_time_re.search(field_data): 161 raise ValidationError, _('Enter a valid time in HH:MM format.') 162 163 def isValidANSIDatetime(field_data, all_data): 164 if not ansi_datetime_re.search(field_data): 165 raise ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 166 _isValidDate(field_data.split()[0]) 167 168 def isValidEmail(field_data, all_data): 169 if not email_re.search(field_data): 170 raise ValidationError, _('Enter a valid e-mail address.') 171 172 def isValidImage(field_data, all_data): 173 """ 174 Checks that the file-upload field data contains a valid image (GIF, JPG, 175 PNG, possibly others -- whatever the Python Imaging Library supports). 176 """ 177 from PIL import Image 178 from cStringIO import StringIO 179 try: 180 content = field_data['content'] 181 except TypeError: 182 raise ValidationError, _("No file was submitted. Check the encoding type on the form.") 183 try: 184 # load() is the only method that can spot a truncated JPEG, 185 # but it cannot be called sanely after verify() 186 trial_image = Image.open(StringIO(content)) 187 trial_image.load() 188 # verify() is the only method that can spot a corrupt PNG, 189 # but it must be called immediately after the constructor 190 trial_image = Image.open(StringIO(content)) 191 trial_image.verify() 192 except Exception: # Python Imaging Library doesn't recognize it as an image 193 raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.") 194 195 def isValidImageURL(field_data, all_data): 196 uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png')) 197 try: 198 uc(field_data, all_data) 199 except URLMimeTypeCheck.InvalidContentType: 200 raise ValidationError, _("The URL %s does not point to a valid image.") % field_data 201 202 def isValidPhone(field_data, all_data): 203 if not phone_re.search(field_data): 204 raise ValidationError, _('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data 205 206 def isValidQuicktimeVideoURL(field_data, all_data): 207 "Checks that the given URL is a video that can be played by QuickTime (qt, mpeg)" 208 uc = URLMimeTypeCheck(('video/quicktime', 'video/mpeg',)) 209 try: 210 uc(field_data, all_data) 211 except URLMimeTypeCheck.InvalidContentType: 212 raise ValidationError, _("The URL %s does not point to a valid QuickTime video.") % field_data 213 214 def isValidURL(field_data, all_data): 215 if not url_re.search(field_data): 216 raise ValidationError, _("A valid URL is required.") 217 218 def isValidHTML(field_data, all_data): 219 import urllib, urllib2 220 try: 221 u = urllib2.urlopen('http://validator.w3.org/check', urllib.urlencode({'fragment': field_data, 'output': 'xml'})) 222 except: 223 # Validator or Internet connection is unavailable. Fail silently. 224 return 225 html_is_valid = (u.headers.get('x-w3c-validator-status', 'Invalid') == 'Valid') 226 if html_is_valid: 227 return 228 from xml.dom.minidom import parseString 229 error_messages = [e.firstChild.wholeText for e in parseString(u.read()).getElementsByTagName('messages')[0].getElementsByTagName('msg')] 230 raise ValidationError, _("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages) 231 232 def isWellFormedXml(field_data, all_data): 233 from xml.dom.minidom import parseString 234 try: 235 parseString(field_data) 236 except Exception, e: # Naked except because we're not sure what will be thrown 237 raise ValidationError, _("Badly formed XML: %s") % str(e) 238 239 def isWellFormedXmlFragment(field_data, all_data): 240 isWellFormedXml('<root>%s</root>' % field_data, all_data) 241 242 def isExistingURL(field_data, all_data): 53 def validate_existing_url(value): 243 54 try: 244 55 headers = { 245 56 "Accept" : "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", … … def isExistingURL(field_data, all_data): 248 59 "Connection" : "close", 249 60 "User-Agent": settings.URL_VALIDATOR_USER_AGENT 250 61 } 251 req = urllib2.Request( field_data,None, headers)62 req = urllib2.Request(value,None, headers) 252 63 u = urllib2.urlopen(req) 253 64 except ValueError: 254 raise ValidationError, _("Invalid URL: %s") % field_data65 raise ValidationError, _("Invalid URL: %s") % value 255 66 except urllib2.HTTPError, e: 256 67 # 401s are valid; they just mean authorization is required. 257 68 # 301 and 302 are redirects; they just mean look somewhere else. 258 69 if str(e.code) not in ('401','301','302'): 259 raise ValidationError, _("The URL %s is a broken link.") % field_data70 raise ValidationError, _("The URL %s is a broken link.") % value 260 71 except: # urllib2.URLError, httplib.InvalidURL, etc. 261 raise ValidationError, _("The URL %s is a broken link.") % field_data 262 263 def isValidUSState(field_data, all_data): 264 "Checks that the given string is a valid two-letter U.S. state abbreviation" 265 states = ['AA', 'AE', 'AK', 'AL', 'AP', 'AR', 'AS', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'FM', 'GA', 'GU', 'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME', 'MH', 'MI', 'MN', 'MO', 'MP', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'PR', 'PW', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VA', 'VI', 'VT', 'WA', 'WI', 'WV', 'WY'] 266 if field_data.upper() not in states: 267 raise ValidationError, _("Enter a valid U.S. state abbreviation.") 268 269 def hasNoProfanities(field_data, all_data): 270 """ 271 Checks that the given string has no profanities in it. This does a simple 272 check for whether each profanity exists within the string, so 'fuck' will 273 catch 'motherfucker' as well. Raises a ValidationError such as: 274 Watch your mouth! The words "f--k" and "s--t" are not allowed here. 275 """ 276 field_data = field_data.lower() # normalize 277 words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data] 278 if words_seen: 279 from django.utils.text import get_text_list 280 plural = len(words_seen) 281 raise ValidationError, ungettext("Watch your mouth! The word %s is not allowed here.", 282 "Watch your mouth! The words %s are not allowed here.", plural) % \ 283 get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], _('and')) 284 285 class AlwaysMatchesOtherField(object): 286 def __init__(self, other_field_name, error_message=None): 287 self.other = other_field_name 288 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must match the '%s' field."), self.other) 289 self.always_test = True 290 291 def __call__(self, field_data, all_data): 292 if field_data != all_data[self.other]: 293 raise ValidationError, self.error_message 294 295 class ValidateIfOtherFieldEquals(object): 296 def __init__(self, other_field, other_value, validator_list): 297 self.other_field, self.other_value = other_field, other_value 298 self.validator_list = validator_list 299 self.always_test = True 300 301 def __call__(self, field_data, all_data): 302 if self.other_field in all_data and all_data[self.other_field] == self.other_value: 303 for v in self.validator_list: 304 v(field_data, all_data) 72 raise ValidationError, _("The URL %s is a broken link.") % value 305 73 306 class RequiredIfOtherFieldNotGiven(object):307 def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter something for at least one field.")):308 self.other, self.error_message = other_field_name, error_message309 self.always_test = True310 311 def __call__(self, field_data, all_data):312 if not all_data.get(self.other, False) and not field_data:313 raise ValidationError, self.error_message314 315 class RequiredIfOtherFieldsGiven(object):316 def __init__(self, other_field_names, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")):317 self.other, self.error_message = other_field_names, error_message318 self.always_test = True319 320 def __call__(self, field_data, all_data):321 for field in self.other:322 if all_data.get(field, False) and not field_data:323 raise ValidationError, self.error_message324 325 class RequiredIfOtherFieldGiven(RequiredIfOtherFieldsGiven):326 "Like RequiredIfOtherFieldsGiven, but takes a single field name instead of a list."327 def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")):328 RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message)329 330 class RequiredIfOtherFieldEquals(object):331 def __init__(self, other_field, other_value, error_message=None, other_label=None):332 self.other_field = other_field333 self.other_value = other_value334 other_label = other_label or other_value335 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is %(value)s"), {336 'field': other_field, 'value': other_label})337 self.always_test = True338 339 def __call__(self, field_data, all_data):340 if self.other_field in all_data and all_data[self.other_field] == self.other_value and not field_data:341 raise ValidationError(self.error_message)342 343 class RequiredIfOtherFieldDoesNotEqual(object):344 def __init__(self, other_field, other_value, other_label=None, error_message=None):345 self.other_field = other_field346 self.other_value = other_value347 other_label = other_label or other_value348 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is not %(value)s"), {349 'field': other_field, 'value': other_label})350 self.always_test = True351 352 def __call__(self, field_data, all_data):353 if self.other_field in all_data and all_data[self.other_field] != self.other_value and not field_data:354 raise ValidationError(self.error_message)355 356 class IsLessThanOtherField(object):357 def __init__(self, other_field_name, error_message):358 self.other, self.error_message = other_field_name, error_message359 360 def __call__(self, field_data, all_data):361 if field_data > all_data[self.other]:362 raise ValidationError, self.error_message363 364 class UniqueAmongstFieldsWithPrefix(object):365 def __init__(self, field_name, prefix, error_message):366 self.field_name, self.prefix = field_name, prefix367 self.error_message = error_message or ugettext_lazy("Duplicate values are not allowed.")368 369 def __call__(self, field_data, all_data):370 for field_name, value in all_data.items():371 if field_name != self.field_name and value == field_data:372 raise ValidationError, self.error_message373 374 class NumberIsInRange(object):375 """376 Validator that tests if a value is in a range (inclusive).377 """378 def __init__(self, lower=None, upper=None, error_message=''):379 self.lower, self.upper = lower, upper380 if not error_message:381 if lower and upper:382 self.error_message = _("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper}383 elif lower:384 self.error_message = _("This value must be at least %s.") % lower385 elif upper:386 self.error_message = _("This value must be no more than %s.") % upper387 else:388 self.error_message = error_message389 390 def __call__(self, field_data, all_data):391 # Try to make the value numeric. If this fails, we assume another392 # validator will catch the problem.393 try:394 val = float(field_data)395 except ValueError:396 return397 398 # Now validate399 if self.lower and self.upper and (val < self.lower or val > self.upper):400 raise ValidationError(self.error_message)401 elif self.lower and val < self.lower:402 raise ValidationError(self.error_message)403 elif self.upper and val > self.upper:404 raise ValidationError(self.error_message)405 406 class IsAPowerOf(object):407 """408 Usage: If you create an instance of the IsPowerOf validator:409 v = IsAPowerOf(2)410 411 The following calls will succeed:412 v(4, None)413 v(8, None)414 v(16, None)415 416 But this call:417 v(17, None)418 will raise "django.core.validators.ValidationError: ['This value must be a power of 2.']"419 """420 def __init__(self, power_of):421 self.power_of = power_of422 423 def __call__(self, field_data, all_data):424 from math import log425 val = log(int(field_data)) / log(self.power_of)426 if val != int(val):427 raise ValidationError, _("This value must be a power of %s.") % self.power_of428 429 class IsValidDecimal(object):430 def __init__(self, max_digits, decimal_places):431 self.max_digits, self.decimal_places = max_digits, decimal_places432 433 def __call__(self, field_data, all_data):434 try:435 val = Decimal(field_data)436 except DecimalException:437 raise ValidationError, _("Please enter a valid decimal number.")438 439 pieces = str(val).lstrip("-").split('.')440 decimals = (len(pieces) == 2) and len(pieces[1]) or 0441 digits = len(pieces[0])442 443 if digits + decimals > self.max_digits:444 raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.",445 "Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits446 if digits > (self.max_digits - self.decimal_places):447 raise ValidationError, ungettext( "Please enter a valid decimal number with a whole part of at most %s digit.",448 "Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places)449 if decimals > self.decimal_places:450 raise ValidationError, ungettext("Please enter a valid decimal number with at most %s decimal place.",451 "Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places452 453 def isValidFloat(field_data, all_data):454 data = smart_str(field_data)455 try:456 float(data)457 except ValueError:458 raise ValidationError, _("Please enter a valid floating point number.")459 460 class HasAllowableSize(object):461 """462 Checks that the file-upload field data is a certain size. min_size and463 max_size are measurements in bytes.464 """465 def __init__(self, min_size=None, max_size=None, min_error_message=None, max_error_message=None):466 self.min_size, self.max_size = min_size, max_size467 self.min_error_message = min_error_message or lazy_inter(ugettext_lazy("Make sure your uploaded file is at least %s bytes big."), min_size)468 self.max_error_message = max_error_message or lazy_inter(ugettext_lazy("Make sure your uploaded file is at most %s bytes big."), max_size)469 470 def __call__(self, field_data, all_data):471 try:472 content = field_data['content']473 except TypeError:474 raise ValidationError, ugettext_lazy("No file was submitted. Check the encoding type on the form.")475 if self.min_size is not None and len(content) < self.min_size:476 raise ValidationError, self.min_error_message477 if self.max_size is not None and len(content) > self.max_size:478 raise ValidationError, self.max_error_message479 480 class MatchesRegularExpression(object):481 """482 Checks that the field matches the given regular-expression. The regex483 should be in string format, not already compiled.484 """485 def __init__(self, regexp, error_message=ugettext_lazy("The format for this field is wrong.")):486 self.regexp = re.compile(regexp)487 self.error_message = error_message488 489 def __call__(self, field_data, all_data):490 if not self.regexp.search(field_data):491 raise ValidationError(self.error_message)492 493 class AnyValidator(object):494 """495 This validator tries all given validators. If any one of them succeeds,496 validation passes. If none of them succeeds, the given message is thrown497 as a validation error. The message is rather unspecific, so it's best to498 specify one on instantiation.499 """500 def __init__(self, validator_list=None, error_message=ugettext_lazy("This field is invalid.")):501 if validator_list is None: validator_list = []502 self.validator_list = validator_list503 self.error_message = error_message504 for v in validator_list:505 if hasattr(v, 'always_test'):506 self.always_test = True507 508 def __call__(self, field_data, all_data):509 for v in self.validator_list:510 try:511 v(field_data, all_data)512 return513 except ValidationError, e:514 pass515 raise ValidationError(self.error_message)516 517 class URLMimeTypeCheck(object):518 "Checks that the provided URL points to a document with a listed mime type"519 class CouldNotRetrieve(ValidationError):520 pass521 class InvalidContentType(ValidationError):522 pass523 524 def __init__(self, mime_type_list):525 self.mime_type_list = mime_type_list526 527 def __call__(self, field_data, all_data):528 import urllib2529 try:530 isValidURL(field_data, all_data)531 except ValidationError:532 raise533 try:534 info = urllib2.urlopen(field_data).info()535 except (urllib2.HTTPError, urllib2.URLError):536 raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data537 content_type = info['content-type']538 if content_type not in self.mime_type_list:539 raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % {540 'url': field_data, 'contenttype': content_type}541 542 class RelaxNGCompact(object):543 "Validate against a Relax NG compact schema"544 def __init__(self, schema_path, additional_root_element=None):545 self.schema_path = schema_path546 self.additional_root_element = additional_root_element547 548 def __call__(self, field_data, all_data):549 import os, tempfile550 if self.additional_root_element:551 field_data = '<%(are)s>%(data)s\n</%(are)s>' % {552 'are': self.additional_root_element,553 'data': field_data554 }555 filename = tempfile.mktemp() # Insecure, but nothing else worked556 fp = open(filename, 'w')557 fp.write(field_data)558 fp.close()559 if not os.path.exists(settings.JING_PATH):560 raise Exception, "%s not found!" % settings.JING_PATH561 p = os.popen('%s -c %s %s' % (settings.JING_PATH, self.schema_path, filename))562 errors = [line.strip() for line in p.readlines()]563 p.close()564 os.unlink(filename)565 display_errors = []566 lines = field_data.split('\n')567 for error in errors:568 ignored, line, level, message = error.split(':', 3)569 # Scrape the Jing error messages to reword them more nicely.570 m = re.search(r'Expected "(.*?)" to terminate element starting on line (\d+)', message)571 if m:572 display_errors.append(_('Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "%(start)s".)') % \573 {'tag':m.group(1).replace('/', ''), 'line':m.group(2), 'start':lines[int(m.group(2)) - 1][:30]})574 continue575 if message.strip() == 'text not allowed here':576 display_errors.append(_('Some text starting on line %(line)s is not allowed in that context. (Line starts with "%(start)s".)') % \577 {'line':line, 'start':lines[int(line) - 1][:30]})578 continue579 m = re.search(r'\s*attribute "(.*?)" not allowed at this point; ignored', message)580 if m:581 display_errors.append(_('"%(attr)s" on line %(line)s is an invalid attribute. (Line starts with "%(start)s".)') % \582 {'attr':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]})583 continue584 m = re.search(r'\s*unknown element "(.*?)"', message)585 if m:586 display_errors.append(_('"<%(tag)s>" on line %(line)s is an invalid tag. (Line starts with "%(start)s".)') % \587 {'tag':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]})588 continue589 if message.strip() == 'required attributes missing':590 display_errors.append(_('A tag on line %(line)s is missing one or more required attributes. (Line starts with "%(start)s".)') % \591 {'line':line, 'start':lines[int(line) - 1][:30]})592 continue593 m = re.search(r'\s*bad value for attribute "(.*?)"', message)594 if m:595 display_errors.append(_('The "%(attr)s" attribute on line %(line)s has an invalid value. (Line starts with "%(start)s".)') % \596 {'attr':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]})597 continue598 # Failing all those checks, use the default error message.599 display_error = 'Line %s: %s [%s]' % (line, message, level.strip())600 display_errors.append(display_error)601 if len(display_errors) > 0:602 raise ValidationError, display_errors -
django/db/models/__init__.py
diff --git a/django/db/models/__init__.py b/django/db/models/__init__.py index 86763d9..afd9151 100644
a b 1 1 from django.conf import settings 2 2 from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured 3 from django.core import validators4 3 from django.db import connection 5 4 from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models 6 5 from django.db.models.query import Q -
django/db/models/base.py
diff --git a/django/db/models/base.py b/django/db/models/base.py index 4f034bc..af9caf1 100644
a b 1 1 import django.db.models.manipulators 2 2 import django.db.models.manager 3 from django.core import validators3 from django.core.validation import ValidationError, NON_FIELD_ERRORS 4 4 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned 5 5 from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist 6 6 from django.db.models.fields.related import OneToOneRel, ManyToOneRel … … from django.dispatch import dispatcher 13 13 from django.utils.datastructures import SortedDict 14 14 from django.utils.functional import curry 15 15 from django.utils.encoding import smart_str, force_unicode, smart_unicode 16 from django.utils.translation import ugettext as _ 16 17 from django.conf import settings 17 18 from itertools import izip 18 19 import types … … class Model(object): 277 278 278 279 save.alters_data = True 279 280 280 def validate(self ):281 def validate(self, form_data=None): 281 282 """ 282 283 First coerces all fields on this instance to their proper Python types. 283 284 Then runs validation on every field. Returns a dictionary of 284 285 field_name -> error_list. 285 286 """ 287 if form_data is not None: 288 def get_value(f): 289 if f.name in form_data: 290 return form_data[f.name] 291 return getattr(self, f.attname, f.get_default()) 292 else: 293 get_value = lambda f: getattr(self, f.attname, f.get_default()) 286 294 error_dict = {} 287 invalid_python = {}288 295 for f in self._meta.fields: 289 296 try: 290 setattr(self, f.attname, f.to_python(getattr(self, f.attname, f.get_default()))) 291 except validators.ValidationError, e: 297 value = f.to_python(get_value(f)) 298 f.validate(value, instance=self) 299 if hasattr(self, 'validate_%s' % f.name): 300 getattr(self, 'validate_%s' % f.name)(value) 301 except ValidationError, e: 292 302 error_dict[f.name] = e.messages 293 invalid_python[f.name] = 1 294 for f in self._meta.fields: 295 if f.name in invalid_python: 296 continue 297 errors = f.validate_full(getattr(self, f.attname, f.get_default()), self.__dict__) 298 if errors: 299 error_dict[f.name] = errors 300 return error_dict 303 304 for un_together in self._meta.unique_together: 305 lookup = {} 306 for name in un_together: 307 if name in error_dict: 308 break 309 f = self._meta.get_field(name) 310 lookup['%s__exact' % name] = f.to_python(get_value(f)) 311 try: 312 qset = self.__class__._default_manager.all() 313 if self.pk: 314 qset = qset.exclude(pk=self.pk) 315 obj = qset.get(**lookup) 316 error_dict[NON_FIELD_ERRORS] = _('Fields %s must be unique.') % ', '.join(un_together) 317 except self.DoesNotExist: 318 pass 319 320 if error_dict: 321 raise ValidationError(error_dict) 301 322 302 323 def _collect_sub_objects(self, seen_objs): 303 324 """ -
django/db/models/fields/__init__.py
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 13a84ec..1233f53 100644
a b from django.db import get_creation_module 10 10 from django.db.models import signals 11 11 from django.dispatch import dispatcher 12 12 from django.conf import settings 13 from django.oldforms import validators as oldvalidators 13 14 from django.core import validators 14 15 from django import oldforms 15 16 from django import newforms as forms … … class Field(object): 78 79 # Tracks each time a Field instance is created. Used to retain order. 79 80 creation_counter = 0 80 81 82 validators = [] 83 81 84 def __init__(self, verbose_name=None, name=None, primary_key=False, 82 85 max_length=None, unique=False, blank=False, null=False, db_index=False, 83 86 core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True, 84 87 prepopulate_from=None, unique_for_date=None, unique_for_month=None, 85 88 unique_for_year=None, validator_list=None, choices=None, radio_admin=None, 86 help_text='', db_column=None, db_tablespace=None ):89 help_text='', db_column=None, db_tablespace=None, validators=[]): 87 90 self.name = name 88 91 self.verbose_name = verbose_name 89 92 self.primary_key = primary_key … … class Field(object): 96 99 self.core, self.rel, self.default = core, rel, default 97 100 self.editable = editable 98 101 self.serialize = serialize 102 self.validators = validators + self.validators 99 103 self.validator_list = validator_list or [] 100 104 self.prepopulate_from = prepopulate_from 101 105 self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month … … class Field(object): 151 155 return None 152 156 return data_types[internal_type] % self.__dict__ 153 157 154 def validate_full(self, field_data, all_data): 155 """ 156 Returns a list of errors for this field. This is the main interface, 157 as it encapsulates some basic validation logic used by all fields. 158 Subclasses should implement validate(), not validate_full(). 159 """ 160 if not self.blank and not field_data: 161 return [_('This field is required.')] 162 try: 163 self.validate(field_data, all_data) 164 except validators.ValidationError, e: 165 return e.messages 166 return [] 167 168 def validate(self, field_data, all_data): 158 def validate(self, value, instance=None): 169 159 """ 170 Raises validators.ValidationError if field_datahas any errors.160 Raises validators.ValidationError if value has any errors. 171 161 Subclasses should override this to specify field-specific validation 172 logic. This method should assume field_datahas already been converted162 logic. This method should assume value has already been converted 173 163 into the appropriate data type by Field.to_python(). 174 164 """ 175 pass 165 if not self.blank and self.editable and not value: 166 raise validators.ValidationError(_('This field is required.')) 167 elist = [] 168 for validator in self.validators: 169 validator(value) 170 if self.unique and instance: 171 try: 172 qset = instance.__class__._default_manager.all() 173 if instance.pk: 174 qset = qset.exclude(pk=instance.pk) 175 obj = qset.get(**{'%s__exact' % self.name : value}) 176 raise validators.ValidationError(_('This field must be unique')) 177 except instance.DoesNotExist: 178 pass 176 179 177 180 def set_attributes_from_name(self, name): 178 181 self.name = name … … class Field(object): 324 327 core_field_names.extend(f.get_manipulator_field_names(name_prefix)) 325 328 # Now, if there are any, add the validator to this FormField. 326 329 if core_field_names: 327 params['validator_list'].append( validators.RequiredIfOtherFieldsGiven(core_field_names, ugettext_lazy("This field is required.")))330 params['validator_list'].append(oldvalidators.RequiredIfOtherFieldsGiven(core_field_names, ugettext_lazy("This field is required."))) 328 331 329 332 # Finally, add the field_names. 330 333 field_names = self.get_manipulator_field_names(name_prefix) … … class DateField(Field): 520 523 return value.date() 521 524 if isinstance(value, datetime.date): 522 525 return value 523 validators.isValidANSIDate(value, None)524 526 try: 525 527 return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3]) 526 528 except ValueError: … … class DecimalField(Field): 713 715 return super(DecimalField, self).formfield(**defaults) 714 716 715 717 class EmailField(CharField): 718 validators = [validators.validate_email] 716 719 def __init__(self, *args, **kwargs): 717 720 kwargs['max_length'] = kwargs.get('max_length', 75) 718 721 CharField.__init__(self, *args, **kwargs) … … class EmailField(CharField): 720 723 def get_manipulator_field_objs(self): 721 724 return [oldforms.EmailField] 722 725 723 def validate(self, field_data, all_data):724 validators.isValidEmail(field_data, all_data)725 726 726 def formfield(self, **kwargs): 727 727 defaults = {'form_class': forms.EmailField} 728 728 defaults.update(kwargs) … … class FileField(Field): 756 756 self.always_test = True 757 757 def __call__(self, field_data, all_data): 758 758 if not all_data.get(self.other_file_field_name, False): 759 c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))759 c = oldvalidators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required.")) 760 760 c(field_data, all_data) 761 761 # First, get the core fields, if any. 762 762 core_field_names = [] … … class FileField(Field): 767 767 if core_field_names: 768 768 field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name)) 769 769 else: 770 v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))770 v = oldvalidators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required.")) 771 771 v.always_test = True 772 772 field_list[0].validator_list.append(v) 773 773 field_list[0].is_required = field_list[1].is_required = False … … class IntegerField(Field): 925 925 926 926 class IPAddressField(Field): 927 927 empty_strings_allowed = False 928 validators = [validators.validate_ip_address4] 929 928 930 def __init__(self, *args, **kwargs): 929 931 kwargs['max_length'] = 15 930 932 Field.__init__(self, *args, **kwargs) … … class IPAddressField(Field): 935 937 def get_internal_type(self): 936 938 return "IPAddressField" 937 939 938 def validate(self, field_data, all_data):939 validators.isValidIPAddress4(field_data, None)940 941 940 def formfield(self, **kwargs): 942 941 defaults = {'form_class': forms.IPAddressField} 943 942 defaults.update(kwargs) … … class NullBooleanField(Field): 968 967 return super(NullBooleanField, self).formfield(**defaults) 969 968 970 969 class PhoneNumberField(IntegerField): 970 validators = [validators.validate_phone_number] 971 971 972 def get_manipulator_field_objs(self): 972 973 return [oldforms.PhoneNumberField] 973 974 974 975 def get_internal_type(self): 975 976 return "PhoneNumberField" 976 977 977 def validate(self, field_data, all_data):978 validators.isValidPhone(field_data, all_data)979 980 978 def formfield(self, **kwargs): 981 979 from django.contrib.localflavor.us.forms import USPhoneNumberField 982 980 defaults = {'form_class': USPhoneNumberField} … … class PositiveSmallIntegerField(IntegerField): 1008 1006 return super(PositiveSmallIntegerField, self).formfield(**defaults) 1009 1007 1010 1008 class SlugField(CharField): 1009 validators = [validators.validate_slug] 1011 1010 def __init__(self, *args, **kwargs): 1012 1011 kwargs['max_length'] = kwargs.get('max_length', 50) 1013 kwargs.setdefault('validator_list', []).append(validators.isSlug)1014 1012 # Set db_index=True unless it's been set manually. 1015 1013 if 'db_index' not in kwargs: 1016 1014 kwargs['db_index'] = True … … class URLField(CharField): 1106 1104 def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): 1107 1105 kwargs['max_length'] = kwargs.get('max_length', 200) 1108 1106 if verify_exists: 1109 kwargs.setdefault('validator _list', []).append(validators.isExistingURL)1107 kwargs.setdefault('validators', []).append(validators.validate_existing_url) 1110 1108 self.verify_exists = verify_exists 1111 1109 CharField.__init__(self, verbose_name, name, **kwargs) 1112 1110 -
django/db/models/fields/related.py
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index c87fdd9..5bcd38c 100644
a b class ManyToManyField(RelatedField, Field): 747 747 objects = mod._default_manager.in_bulk(pks) 748 748 if len(objects) != len(pks): 749 749 badkeys = [k for k in pks if k not in objects] 750 raise validator s.ValidationError, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.",750 raise validator_list.ValidationError, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.", 751 751 "Please enter valid %(self)s IDs. The values %(value)r are invalid.", len(badkeys)) % { 752 752 'self': self.verbose_name, 753 753 'value': len(badkeys) == 1 and badkeys[0] or tuple(badkeys), -
django/newforms/__init__.py
diff --git a/django/newforms/__init__.py b/django/newforms/__init__.py index 0d9c68f..6f881f0 100644
a b TODO: 10 10 "This form field requires foo.js" and form.js_includes() 11 11 """ 12 12 13 from utilimport ValidationError13 from django.core.validation import ValidationError 14 14 from widgets import * 15 15 from fields import * 16 16 from forms import * -
django/newforms/fields.py
diff --git a/django/newforms/fields.py b/django/newforms/fields.py index 08e8b84..61e815d 100644
a b except NameError: 19 19 20 20 from django.utils.translation import ugettext_lazy as _ 21 21 from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str 22 from django.core.validation import ValidationError, ErrorList, TypeCoersionError 22 23 23 from util import ErrorList, ValidationError24 24 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput 25 25 26 26 … … EMPTY_VALUES = (None, '') 41 41 42 42 class Field(object): 43 43 widget = TextInput # Default widget to use when rendering this type of Field. 44 validators = [] 44 45 hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden". 45 46 default_error_messages = { 46 47 'required': _(u'This field is required.'), … … class Field(object): 51 52 creation_counter = 0 52 53 53 54 def __init__(self, required=True, widget=None, label=None, initial=None, 54 help_text=None, error_messages=None ):55 help_text=None, error_messages=None, validators=[]): 55 56 # required -- Boolean that specifies whether the field is required. 56 57 # True by default. 57 58 # widget -- A Widget class, or instance of a Widget class, that should … … class Field(object): 65 66 # initial -- A value to use in this Field's initial display. This value 66 67 # is *not* used as a fallback if data isn't given. 67 68 # help_text -- An optional string to use as "help text" for this Field. 69 # validators -- Optional list of additional validator functions 68 70 if label is not None: 69 71 label = smart_unicode(label) 72 self.validators = self.validators + validators 70 73 self.required, self.label, self.initial = required, label, initial 71 74 self.help_text = smart_unicode(help_text or '') 72 75 widget = widget or self.widget … … class Field(object): 94 97 messages.update(error_messages or {}) 95 98 self.error_messages = messages 96 99 100 def to_python(self, value): 101 return self.clean(value) 102 103 def validate(self, value): 104 if self.required and value in EMPTY_VALUES: 105 raise ValidationError(self.error_messages['required']) 106 elist = ErrorList() 107 for validator in self.validators: 108 try: 109 validator(value) 110 except ValidationError, e: 111 elist.extend(e.messages) 112 if elist: 113 raise ValidationError(elist) 114 97 115 def clean(self, value): 98 116 """ 99 117 Validates the given value and returns its "cleaned" value as an … … class Field(object): 119 137 result.widget = copy.deepcopy(self.widget, memo) 120 138 return result 121 139 122 class CharField(Field): 140 class LegacyField(Field): 141 def to_python(self, value): 142 if value in EMPTY_VALUES: 143 return u'' 144 return smart_unicode(value) 145 146 def clean(self, value): 147 value = self.to_python(value) 148 self.validate(value) 149 return value 150 151 class CharField(LegacyField): 123 152 default_error_messages = { 124 153 'max_length': _(u'Ensure this value has at most %(max)d characters (it has %(length)d).'), 125 154 'min_length': _(u'Ensure this value has at least %(min)d characters (it has %(length)d).'), … … class CharField(Field): 129 158 self.max_length, self.min_length = max_length, min_length 130 159 super(CharField, self).__init__(*args, **kwargs) 131 160 132 def clean(self, value):161 def validate(self, value): 133 162 "Validates max_length and min_length. Returns a Unicode object." 134 super(CharField, self).clean(value) 135 if value in EMPTY_VALUES: 136 return u'' 137 value = smart_unicode(value) 163 super(CharField, self).validate(value) 138 164 value_length = len(value) 165 if value_length == 0 and not self.required: 166 return 139 167 if self.max_length is not None and value_length > self.max_length: 140 168 raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length}) 141 169 if self.min_length is not None and value_length < self.min_length: 142 170 raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length}) 143 return value144 171 145 172 def widget_attrs(self, widget): 146 173 if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)): 147 174 # The HTML attribute is maxlength, not max_length. 148 175 return {'maxlength': str(self.max_length)} 149 176 150 class IntegerField( Field):177 class IntegerField(LegacyField): 151 178 default_error_messages = { 152 179 'invalid': _(u'Enter a whole number.'), 153 180 'max_value': _(u'Ensure this value is less than or equal to %s.'), … … class IntegerField(Field): 158 185 self.max_value, self.min_value = max_value, min_value 159 186 super(IntegerField, self).__init__(*args, **kwargs) 160 187 161 def clean(self, value): 162 """ 163 Validates that int() can be called on the input. Returns the result 164 of int(). Returns None for empty values. 165 """ 166 super(IntegerField, self).clean(value) 188 def to_python(self, value): 167 189 if value in EMPTY_VALUES: 168 190 return None 169 191 try: 170 value = int(str(value))192 return int(smart_str(value)) 171 193 except (ValueError, TypeError): 172 raise ValidationError(self.error_messages['invalid']) 194 raise TypeCoersionError(self.error_messages['invalid']) 195 196 def validate(self, value): 197 """ 198 Validates that int() can be called on the input. Returns the result 199 of int(). Returns None for empty values. 200 """ 201 super(IntegerField, self).validate(value) 202 if value is None: return 173 203 if self.max_value is not None and value > self.max_value: 174 204 raise ValidationError(self.error_messages['max_value'] % self.max_value) 175 205 if self.min_value is not None and value < self.min_value: 176 206 raise ValidationError(self.error_messages['min_value'] % self.min_value) 177 return value178 207 179 class FloatField( Field):208 class FloatField(LegacyField): 180 209 default_error_messages = { 181 210 'invalid': _(u'Enter a number.'), 182 211 'max_value': _(u'Ensure this value is less than or equal to %s.'), … … class FloatField(Field): 187 216 self.max_value, self.min_value = max_value, min_value 188 217 Field.__init__(self, *args, **kwargs) 189 218 190 def clean(self, value):219 def to_python(self, value): 191 220 """ 192 221 Validates that float() can be called on the input. Returns a float. 193 222 Returns None for empty values. 194 223 """ 195 super(FloatField, self).clean(value) 196 if not self.required and value in EMPTY_VALUES: 224 if value in EMPTY_VALUES: 197 225 return None 198 226 try: 199 value =float(value)227 return float(value) 200 228 except (ValueError, TypeError): 201 raise ValidationError(self.error_messages['invalid']) 229 raise TypeCoersionError(self.error_messages['invalid']) 230 231 def validate(self, value): 232 super(FloatField, self).validate(value) 233 if value is None: return 202 234 if self.max_value is not None and value > self.max_value: 203 235 raise ValidationError(self.error_messages['max_value'] % self.max_value) 204 236 if self.min_value is not None and value < self.min_value: 205 237 raise ValidationError(self.error_messages['min_value'] % self.min_value) 206 return value207 238 208 class DecimalField( Field):239 class DecimalField(LegacyField): 209 240 default_error_messages = { 210 241 'invalid': _(u'Enter a number.'), 211 242 'max_value': _(u'Ensure this value is less than or equal to %s.'), … … class DecimalField(Field): 220 251 self.max_digits, self.decimal_places = max_digits, decimal_places 221 252 Field.__init__(self, *args, **kwargs) 222 253 223 def clean(self, value):254 def to_python(self, value): 224 255 """ 225 256 Validates that the input is a decimal number. Returns a Decimal 226 257 instance. Returns None for empty values. Ensures that there are no more 227 258 than max_digits in the number, and no more than decimal_places digits 228 259 after the decimal point. 229 260 """ 230 super(DecimalField, self).clean(value) 231 if not self.required and value in EMPTY_VALUES: 261 if value in EMPTY_VALUES: 232 262 return None 233 263 value = smart_str(value).strip() 234 264 try: 235 value =Decimal(value)265 return Decimal(value) 236 266 except DecimalException: 237 raise ValidationError(self.error_messages['invalid']) 267 raise TypeCoersionError(self.error_messages['invalid']) 268 269 def validate(self, value): 270 super(DecimalField, self).validate(value) 271 if value is None: return 238 272 pieces = str(value).lstrip("-").split('.') 239 273 decimals = (len(pieces) == 2) and len(pieces[1]) or 0 240 274 digits = len(pieces[0]) … … class DecimalField(Field): 248 282 raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places) 249 283 if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places): 250 284 raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) 251 return value252 285 253 286 DEFAULT_DATE_INPUT_FORMATS = ( 254 287 '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' … … DEFAULT_DATE_INPUT_FORMATS = ( 258 291 '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006' 259 292 ) 260 293 261 class DateField( Field):294 class DateField(LegacyField): 262 295 default_error_messages = { 263 296 'invalid': _(u'Enter a valid date.'), 264 297 } … … class DateField(Field): 267 300 super(DateField, self).__init__(*args, **kwargs) 268 301 self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS 269 302 270 def clean(self, value):303 def to_python(self, value): 271 304 """ 272 305 Validates that the input can be converted to a date. Returns a Python 273 306 datetime.date object. 274 307 """ 275 super(DateField, self).clean(value)276 308 if value in EMPTY_VALUES: 277 309 return None 278 310 if isinstance(value, datetime.datetime): … … class DateField(Field): 284 316 return datetime.date(*time.strptime(value, format)[:3]) 285 317 except ValueError: 286 318 continue 287 raise ValidationError(self.error_messages['invalid'])319 raise TypeCoersionError(self.error_messages['invalid']) 288 320 289 321 DEFAULT_TIME_INPUT_FORMATS = ( 290 322 '%H:%M:%S', # '14:30:59' 291 323 '%H:%M', # '14:30' 292 324 ) 293 325 294 class TimeField( Field):326 class TimeField(LegacyField): 295 327 default_error_messages = { 296 328 'invalid': _(u'Enter a valid time.') 297 329 } … … class TimeField(Field): 300 332 super(TimeField, self).__init__(*args, **kwargs) 301 333 self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS 302 334 303 def clean(self, value):335 def to_python(self, value): 304 336 """ 305 337 Validates that the input can be converted to a time. Returns a Python 306 338 datetime.time object. 307 339 """ 308 super(TimeField, self).clean(value)309 340 if value in EMPTY_VALUES: 310 341 return None 311 342 if isinstance(value, datetime.time): … … class TimeField(Field): 315 346 return datetime.time(*time.strptime(value, format)[3:6]) 316 347 except ValueError: 317 348 continue 318 raise ValidationError(self.error_messages['invalid'])349 raise TypeCoersionError(self.error_messages['invalid']) 319 350 320 351 DEFAULT_DATETIME_INPUT_FORMATS = ( 321 352 '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' … … DEFAULT_DATETIME_INPUT_FORMATS = ( 329 360 '%m/%d/%y', # '10/25/06' 330 361 ) 331 362 332 class DateTimeField( Field):363 class DateTimeField(LegacyField): 333 364 widget = DateTimeInput 334 365 default_error_messages = { 335 366 'invalid': _(u'Enter a valid date/time.'), … … class DateTimeField(Field): 339 370 super(DateTimeField, self).__init__(*args, **kwargs) 340 371 self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS 341 372 342 def clean(self, value):373 def to_python(self, value): 343 374 """ 344 375 Validates that the input can be converted to a datetime. Returns a 345 376 Python datetime.datetime object. 346 377 """ 347 super(DateTimeField, self).clean(value)348 378 if value in EMPTY_VALUES: 349 379 return None 350 380 if isinstance(value, datetime.datetime): … … class DateTimeField(Field): 362 392 return datetime.datetime(*time.strptime(value, format)[:6]) 363 393 except ValueError: 364 394 continue 365 raise ValidationError(self.error_messages['invalid'])395 raise TypeCoersionError(self.error_messages['invalid']) 366 396 367 397 class RegexField(CharField): 368 398 def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs): … … class RegexField(CharField): 381 411 regex = re.compile(regex) 382 412 self.regex = regex 383 413 384 def clean(self, value):414 def validate(self, value): 385 415 """ 386 416 Validates that the input matches the regular expression. Returns a 387 417 Unicode object. 388 418 """ 389 value = super(RegexField, self).clean(value)390 if value == u'':391 return value419 super(RegexField, self).validate(value) 420 if value in EMPTY_VALUES: 421 return u'' 392 422 if not self.regex.search(value): 393 423 raise ValidationError(self.error_messages['invalid']) 394 return value395 424 396 425 email_re = re.compile( 397 426 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom … … class UploadedFile(StrAndUnicode): 427 456 """ 428 457 return self.filename 429 458 430 class FileField( Field):459 class FileField(LegacyField): 431 460 widget = FileInput 432 461 default_error_messages = { 433 462 'invalid': _(u"No file was submitted. Check the encoding type on the form."), 434 'missing': _(u"No file was submitted."),435 463 'empty': _(u"The submitted file is empty."), 436 464 } 437 465 438 def __init__(self, *args, **kwargs): 439 super(FileField, self).__init__(*args, **kwargs) 440 441 def clean(self, data, initial=None): 442 super(FileField, self).clean(initial or data) 466 def to_python(self, data, initial=None): 443 467 if not self.required and data in EMPTY_VALUES: 444 468 return None 445 469 elif not data and initial: 446 470 return initial 471 elif not data: 472 return None 473 447 474 try: 448 475 f = UploadedFile(data['filename'], data['content']) 449 476 except TypeError: 450 raise ValidationError(self.error_messages['invalid'])477 raise TypeCoersionError(self.error_messages['invalid']) 451 478 except KeyError: 452 raise ValidationError(self.error_messages[' missing'])479 raise ValidationError(self.error_messages['required']) 453 480 if not f.content: 454 481 raise ValidationError(self.error_messages['empty']) 455 482 return f 456 483 484 def clean(self, data, initial=None): 485 value = self.to_python(data, initial) 486 self.validate(value) 487 return value 488 457 489 class ImageField(FileField): 458 490 default_error_messages = { 459 491 'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."), 460 492 } 461 493 462 def clean(self, data, initial=None):494 def validate(self, value): 463 495 """ 464 496 Checks that the file-upload field data contains a valid image (GIF, JPG, 465 497 PNG, possibly others -- whatever the Python Imaging Library supports). 466 498 """ 467 f = super(ImageField, self).clean(data, initial) 468 if f is None: 469 return None 470 elif not data and initial: 471 return initial 499 super(ImageField, self).validate(value) 500 501 if value is None: 502 return 472 503 from PIL import Image 473 504 from cStringIO import StringIO 474 505 try: 475 506 # load() is the only method that can spot a truncated JPEG, 476 507 # but it cannot be called sanely after verify() 477 trial_image = Image.open(StringIO( f.content))508 trial_image = Image.open(StringIO(value.content)) 478 509 trial_image.load() 479 510 # verify() is the only method that can spot a corrupt PNG, 480 511 # but it must be called immediately after the constructor 481 trial_image = Image.open(StringIO( f.content))512 trial_image = Image.open(StringIO(value.content)) 482 513 trial_image.verify() 483 514 except Exception: # Python Imaging Library doesn't recognize it as an image 484 515 raise ValidationError(self.error_messages['invalid_image']) 485 return f486 516 487 517 url_re = re.compile( 488 518 r'^https?://' # http:// or https:// … … class URLField(RegexField): 505 535 self.verify_exists = verify_exists 506 536 self.user_agent = validator_user_agent 507 537 508 def clean(self, value):509 # If no URL scheme given, assume http://538 def to_python(self, value): 539 value = super(URLField, self).to_python(value) 510 540 if value and '://' not in value: 511 541 value = u'http://%s' % value 512 value = super(URLField, self).clean(value) 513 if value == u'': 514 return value 542 return value 543 544 def validate(self, value): 545 # If no URL scheme given, assume http:// 546 super(URLField, self).validate(value) 547 if value in EMPTY_VALUES: 548 return 515 549 if self.verify_exists: 516 550 import urllib2 517 551 from django.conf import settings … … class URLField(RegexField): 529 563 raise ValidationError(self.error_messages['invalid']) 530 564 except: # urllib2.URLError, httplib.InvalidURL, etc. 531 565 raise ValidationError(self.error_messages['invalid_link']) 532 return value533 566 534 class BooleanField( Field):567 class BooleanField(LegacyField): 535 568 widget = CheckboxInput 536 569 537 def clean(self, value):570 def to_python(self, value): 538 571 """Returns a Python boolean object.""" 539 super(BooleanField, self).clean(value) 572 if self.required and value in EMPTY_VALUES: 573 raise ValidationError(self.error_messages['required']) 540 574 # Explicitly check for the string 'False', which is what a hidden field 541 575 # will submit for False. Because bool("True") == True, we don't need to 542 576 # handle that explicitly. … … class BooleanField(Field): 544 578 return False 545 579 return bool(value) 546 580 581 547 582 class NullBooleanField(BooleanField): 548 583 """ 549 584 A field whose valid values are None, True and False. Invalid values are 550 585 cleaned to None. 586 587 Note that validation doesn't apply here. 551 588 """ 552 589 widget = NullBooleanSelect 553 590 554 def clean(self, value):591 def to_python(self, value): 555 592 return {True: True, False: False}.get(value, None) 556 593 557 class ChoiceField(Field): 594 def validate(self, value): 595 pass 596 597 598 class ChoiceField(LegacyField): 558 599 widget = Select 559 600 default_error_messages = { 560 601 'invalid_choice': _(u'Select a valid choice. That choice is not one of the available choices.'), … … class ChoiceField(Field): 577 618 578 619 choices = property(_get_choices, _set_choices) 579 620 580 def clean(self, value): 581 """ 582 Validates that the input is in self.choices. 583 """ 584 value = super(ChoiceField, self).clean(value) 585 if value in EMPTY_VALUES: 586 value = u'' 587 value = smart_unicode(value) 588 if value == u'': 589 return value 621 def validate(self, value): 622 super(ChoiceField, self).validate(value) 623 if value in EMPTY_VALUES and not self.required: 624 return u'' 590 625 valid_values = set([smart_unicode(k) for k, v in self.choices]) 591 626 if value not in valid_values: 592 627 raise ValidationError(self.error_messages['invalid_choice'] % {'value': value}) 593 return value594 628 595 629 class MultipleChoiceField(ChoiceField): 596 630 hidden_widget = MultipleHiddenInput … … class MultipleChoiceField(ChoiceField): 600 634 'invalid_list': _(u'Enter a list of values.'), 601 635 } 602 636 603 def clean(self, value):637 def to_python(self, value): 604 638 """ 605 639 Validates that the input is a list or tuple. 606 640 """ 607 if self.required and not value: 608 raise ValidationError(self.error_messages['required']) 609 elif not self.required and not value: 641 if not value: 610 642 return [] 611 643 if not isinstance(value, (list, tuple)): 612 raise ValidationError(self.error_messages['invalid_list']) 613 new_value = [smart_unicode(val) for val in value] 644 raise TypeCoersionError(self.error_messages['invalid_list']) 645 return [smart_unicode(val) for val in value] 646 647 def validate(self, value): 614 648 # Validate that each value in the value list is in self.choices. 649 if self.required and value == []: 650 raise ValidationError(self.error_messages['required']) 615 651 valid_values = set([smart_unicode(k) for k, v in self.choices]) 616 for val in new_value:652 for val in value: 617 653 if val not in valid_values: 618 654 raise ValidationError(self.error_messages['invalid_choice'] % {'value': val}) 619 return new_value620 655 621 class ComboField( Field):656 class ComboField(LegacyField): 622 657 """ 623 658 A Field whose clean() method calls multiple Field clean() methods. 624 659 """ … … class ComboField(Field): 631 666 f.required = False 632 667 self.fields = fields 633 668 634 def clean(self, value): 669 def to_python(self, value): 670 for field in self.fields: 671 value = field.to_python(value) 672 return value 673 674 def validate(self, value): 635 675 """ 636 676 Validates the given value against all of self.fields, which is a 637 677 list of Field instances. 638 678 """ 639 super(ComboField, self). clean(value)679 super(ComboField, self).validate(value) 640 680 for field in self.fields: 641 value = field.clean(value) 642 return value 681 field.validate(value) 643 682 644 class MultiValueField( Field):683 class MultiValueField(LegacyField): 645 684 """ 646 685 A Field that aggregates the logic of multiple Fields. 647 686 … … class MultiValueField(Field): 671 710 f.required = False 672 711 self.fields = fields 673 712 674 def clean(self, value):713 def to_python(self, value): 675 714 """ 676 715 Validates every value in the given list. A value is validated against 677 716 the corresponding Field in self.fields. … … class MultiValueField(Field): 685 724 if not value or isinstance(value, (list, tuple)): 686 725 if not value or not [v for v in value if v not in EMPTY_VALUES]: 687 726 if self.required: 688 r aise ValidationError(self.error_messages['required'])727 return None 689 728 else: 690 729 return self.compress([]) 691 730 else: 692 raise ValidationError(self.error_messages['invalid']) 731 raise TypeCoersionError(self.error_messages['invalid']) 732 693 733 for i, field in enumerate(self.fields): 694 734 try: 695 735 field_value = value[i] -
django/newforms/forms.py
diff --git a/django/newforms/forms.py b/django/newforms/forms.py index 2c481e4..f797b0b 100644
a b from django.utils.datastructures import SortedDict 8 8 from django.utils.html import escape 9 9 from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode 10 10 from django.utils.safestring import mark_safe 11 from django.core.validation import ValidationError, ErrorList, NON_FIELD_ERRORS 11 12 12 13 from fields import Field, FileField 13 14 from widgets import TextInput, Textarea 14 from util import flatatt, ErrorDict , ErrorList, ValidationError15 from util import flatatt, ErrorDict 15 16 16 17 __all__ = ('BaseForm', 'Form') 17 18 18 NON_FIELD_ERRORS = '__all__'19 19 20 20 def pretty_name(name): 21 21 "Converts 'first_name' to 'First name'" … … class BaseForm(StrAndUnicode): 201 201 try: 202 202 if isinstance(field, FileField): 203 203 initial = self.initial.get(name, field.initial) 204 value = field. clean(value, initial)204 value = field.to_python(value, initial) 205 205 else: 206 value = field.clean(value) 206 value = field.to_python(value) 207 field.validate(value) 207 208 self.cleaned_data[name] = value 209 # FIXME deprecated - keeping this here for backwards compatibility 208 210 if hasattr(self, 'clean_%s' % name): 209 211 value = getattr(self, 'clean_%s' % name)() 210 212 self.cleaned_data[name] = value 213 214 if hasattr(self, 'validate_%s' % name): 215 getattr(self, 'validate_%s' % name)(value) 211 216 except ValidationError, e: 212 217 self._errors[name] = e.messages 213 218 if name in self.cleaned_data: 214 219 del self.cleaned_data[name] 215 220 try: 216 self. cleaned_data = self.clean()221 self.validate() 217 222 except ValidationError, e: 218 self._errors[NON_FIELD_ERRORS] = e.messages 223 if hasattr(e, 'message_dict'): 224 for k, v in e.message_dict.items(): 225 self._errors.setdefault(k, []).extend(v) 226 else: 227 self._errors[NON_FIELD_ERRORS] = e.messages 219 228 if self._errors: 220 229 delattr(self, 'cleaned_data') 221 230 222 231 def clean(self): 223 232 """ 233 FIXME: deprecated, use validate() instead 234 224 235 Hook for doing any extra form-wide cleaning after Field.clean() been 225 236 called on every field. Any ValidationError raised by this method will 226 237 not be associated with a particular field; it will have a special-case … … class BaseForm(StrAndUnicode): 228 239 """ 229 240 return self.cleaned_data 230 241 242 def validate(self): 243 self.cleaned_data = self.clean() 244 231 245 def is_multipart(self): 232 246 """ 233 247 Returns True if the form needs to be multipart-encrypted, i.e. it has -
django/newforms/models.py
diff --git a/django/newforms/models.py b/django/newforms/models.py index 0590839..5c4b0a4 100644
a b from django.utils.translation import ugettext_lazy as _ 9 9 from django.utils.encoding import smart_unicode 10 10 from django.utils.datastructures import SortedDict 11 11 from django.core.exceptions import ImproperlyConfigured 12 from django.core.validation import ValidationError, ErrorList, TypeCoersionError 12 13 13 from util import ValidationError, ErrorList14 14 from forms import BaseForm, get_declared_fields 15 15 from fields import Field, ChoiceField, EMPTY_VALUES 16 16 from widgets import Select, SelectMultiple, MultipleHiddenInput … … class BaseModelForm(BaseForm): 257 257 object_data.update(initial) 258 258 BaseForm.__init__(self, data, files, auto_id, prefix, object_data, error_class, label_suffix) 259 259 260 def validate(self): 261 super(BaseModelForm, self).validate() 262 if self._errors: 263 return 264 self.instance.validate(self.cleaned_data) 265 260 266 def save(self, commit=True): 261 267 """ 262 268 Saves this ``form``'s cleaned_data into model instance … … class ModelChoiceField(ChoiceField): 354 360 355 361 choices = property(_get_choices, _set_choices) 356 362 357 def clean(self, value): 358 Field.clean(self, value) 359 if value in EMPTY_VALUES: 363 def to_python(self, value): 364 if self.required and value in EMPTY_VALUES: 365 raise ValidationError(self.error_messages['required']) 366 elif value in EMPTY_VALUES: 360 367 return None 361 368 try: 362 369 value = self.queryset.get(pk=value) … … class ModelChoiceField(ChoiceField): 364 371 raise ValidationError(self.error_messages['invalid_choice']) 365 372 return value 366 373 374 def validate(self, value): 375 pass 376 367 377 class ModelMultipleChoiceField(ModelChoiceField): 368 378 """A MultipleChoiceField whose choices are a model QuerySet.""" 369 379 hidden_widget = MultipleHiddenInput … … class ModelMultipleChoiceField(ModelChoiceField): 380 390 cache_choices, required, widget, label, initial, help_text, 381 391 *args, **kwargs) 382 392 383 def clean(self, value):393 def to_python(self, value): 384 394 if self.required and not value: 385 395 raise ValidationError(self.error_messages['required']) 386 396 elif not self.required and not value: 387 397 return [] 388 398 if not isinstance(value, (list, tuple)): 389 raise ValidationError(self.error_messages['list'])399 raise TypeCoersionError(self.error_messages['list']) 390 400 final_values = [] 391 401 for val in value: 392 402 try: … … class ModelMultipleChoiceField(ModelChoiceField): 396 406 else: 397 407 final_values.append(obj) 398 408 return final_values 409 -
django/newforms/util.py
diff --git a/django/newforms/util.py b/django/newforms/util.py index b3edf41..89b93d6 100644
a b class ErrorDict(dict, StrAndUnicode): 30 30 def as_text(self): 31 31 return u'\n'.join([u'* %s\n%s' % (k, u'\n'.join([u' * %s' % force_unicode(i) for i in v])) for k, v in self.items()]) 32 32 33 class ErrorList(list, StrAndUnicode):34 """35 A collection of errors that knows how to display itself in various formats.36 """37 def __unicode__(self):38 return self.as_ul()39 40 def as_ul(self):41 if not self: return u''42 return mark_safe(u'<ul class="errorlist">%s</ul>'43 % ''.join([u'<li>%s</li>' % force_unicode(e) for e in self]))44 45 def as_text(self):46 if not self: return u''47 return u'\n'.join([u'* %s' % force_unicode(e) for e in self])48 49 def __repr__(self):50 return repr([force_unicode(e) for e in self])51 52 class ValidationError(Exception):53 def __init__(self, message):54 """55 ValidationError can be passed any object that can be printed (usually56 a string) or a list of objects.57 """58 if isinstance(message, list):59 self.messages = ErrorList([smart_unicode(msg) for msg in message])60 else:61 message = smart_unicode(message)62 self.messages = ErrorList([message])63 64 def __str__(self):65 # This is needed because, without a __str__(), printing an exception66 # instance would result in this:67 # AttributeError: ValidationError instance has no attribute 'args'68 # See http://www.python.org/doc/current/tut/node10.html#handling69 return repr(self.messages) -
django/oldforms/__init__.py
diff --git a/django/oldforms/__init__.py b/django/oldforms/__init__.py index fc87271..b7b0d10 100644
a b 1 from django. coreimport validators1 from django.oldforms import validators 2 2 from django.core.exceptions import PermissionDenied 3 3 from django.utils.html import escape 4 4 from django.utils.safestring import mark_safe -
new file django/oldforms/validators.py
diff --git a/django/oldforms/validators.py b/django/oldforms/validators.py new file mode 100644 index 0000000..0ff85c7
- + 1 """ 2 A library of validators that return None and raise ValidationError when the 3 provided data isn't valid. 4 5 Validators may be callable classes, and they may have an 'always_test' 6 attribute. If an 'always_test' attribute exists (regardless of value), the 7 validator will *always* be run, regardless of whether its associated 8 form field is required. 9 """ 10 11 import urllib2 12 import re 13 try: 14 from decimal import Decimal, DecimalException 15 except ImportError: 16 from django.utils._decimal import Decimal, DecimalException # Python 2.3 17 18 from django.conf import settings 19 from django.utils.translation import ugettext as _, ugettext_lazy, ungettext 20 from django.utils.functional import Promise, lazy 21 from django.utils.encoding import force_unicode, smart_str 22 from django.core.validation import ValidationError 23 24 _datere = r'\d{4}-\d{1,2}-\d{1,2}' 25 _timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?' 26 alnum_re = re.compile(r'^\w+$') 27 alnumurl_re = re.compile(r'^[-\w/]+$') 28 ansi_date_re = re.compile('^%s$' % _datere) 29 ansi_time_re = re.compile('^%s$' % _timere) 30 ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere)) 31 email_re = re.compile( 32 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom 33 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string 34 r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain 35 integer_re = re.compile(r'^-?\d+$') 36 ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$') 37 phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE) 38 slug_re = re.compile(r'^[-\w]+$') 39 url_re = re.compile(r'^https?://\S+$') 40 41 lazy_inter = lazy(lambda a,b: force_unicode(a) % b, unicode) 42 43 44 class CriticalValidationError(Exception): 45 def __init__(self, message): 46 "ValidationError can be passed a string or a list." 47 if isinstance(message, list): 48 self.messages = [force_unicode(msg) for msg in message] 49 else: 50 assert isinstance(message, (basestring, Promise)), ("'%s' should be a string" % message) 51 self.messages = [force_unicode(message)] 52 53 def __str__(self): 54 return str(self.messages) 55 56 57 def isAlphaNumeric(field_data, all_data): 58 if not alnum_re.search(field_data): 59 raise ValidationError, _("This value must contain only letters, numbers and underscores.") 60 61 def isAlphaNumericURL(field_data, all_data): 62 if not alnumurl_re.search(field_data): 63 raise ValidationError, _("This value must contain only letters, numbers, underscores, dashes or slashes.") 64 65 def isSlug(field_data, all_data): 66 if not slug_re.search(field_data): 67 raise ValidationError, _("This value must contain only letters, numbers, underscores or hyphens.") 68 69 def isLowerCase(field_data, all_data): 70 if field_data.lower() != field_data: 71 raise ValidationError, _("Uppercase letters are not allowed here.") 72 73 def isUpperCase(field_data, all_data): 74 if field_data.upper() != field_data: 75 raise ValidationError, _("Lowercase letters are not allowed here.") 76 77 def isCommaSeparatedIntegerList(field_data, all_data): 78 for supposed_int in field_data.split(','): 79 try: 80 int(supposed_int) 81 except ValueError: 82 raise ValidationError, _("Enter only digits separated by commas.") 83 84 def isCommaSeparatedEmailList(field_data, all_data): 85 """ 86 Checks that field_data is a string of e-mail addresses separated by commas. 87 Blank field_data values will not throw a validation error, and whitespace 88 is allowed around the commas. 89 """ 90 for supposed_email in field_data.split(','): 91 try: 92 isValidEmail(supposed_email.strip(), '') 93 except ValidationError: 94 raise ValidationError, _("Enter valid e-mail addresses separated by commas.") 95 96 def isValidIPAddress4(field_data, all_data): 97 if not ip4_re.search(field_data): 98 raise ValidationError, _("Please enter a valid IP address.") 99 100 def isNotEmpty(field_data, all_data): 101 if field_data.strip() == '': 102 raise ValidationError, _("Empty values are not allowed here.") 103 104 def isOnlyDigits(field_data, all_data): 105 if not field_data.isdigit(): 106 raise ValidationError, _("Non-numeric characters aren't allowed here.") 107 108 def isNotOnlyDigits(field_data, all_data): 109 if field_data.isdigit(): 110 raise ValidationError, _("This value can't be comprised solely of digits.") 111 112 def isInteger(field_data, all_data): 113 # This differs from isOnlyDigits because this accepts the negative sign 114 if not integer_re.search(field_data): 115 raise ValidationError, _("Enter a whole number.") 116 117 def isOnlyLetters(field_data, all_data): 118 if not field_data.isalpha(): 119 raise ValidationError, _("Only alphabetical characters are allowed here.") 120 121 def _isValidDate(date_string): 122 """ 123 A helper function used by isValidANSIDate and isValidANSIDatetime to 124 check if the date is valid. The date string is assumed to already be in 125 YYYY-MM-DD format. 126 """ 127 from datetime import date 128 # Could use time.strptime here and catch errors, but datetime.date below 129 # produces much friendlier error messages. 130 year, month, day = map(int, date_string.split('-')) 131 # This check is needed because strftime is used when saving the date 132 # value to the database, and strftime requires that the year be >=1900. 133 if year < 1900: 134 raise ValidationError, _('Year must be 1900 or later.') 135 try: 136 date(year, month, day) 137 except ValueError, e: 138 msg = _('Invalid date: %s') % _(str(e)) 139 raise ValidationError, msg 140 141 def isValidANSIDate(field_data, all_data): 142 if not ansi_date_re.search(field_data): 143 raise ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 144 _isValidDate(field_data) 145 146 def isValidANSITime(field_data, all_data): 147 if not ansi_time_re.search(field_data): 148 raise ValidationError, _('Enter a valid time in HH:MM format.') 149 150 def isValidANSIDatetime(field_data, all_data): 151 if not ansi_datetime_re.search(field_data): 152 raise ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 153 _isValidDate(field_data.split()[0]) 154 155 def isValidEmail(field_data, all_data): 156 if not email_re.search(field_data): 157 raise ValidationError, _('Enter a valid e-mail address.') 158 159 def isValidImage(field_data, all_data): 160 """ 161 Checks that the file-upload field data contains a valid image (GIF, JPG, 162 PNG, possibly others -- whatever the Python Imaging Library supports). 163 """ 164 from PIL import Image 165 from cStringIO import StringIO 166 try: 167 content = field_data['content'] 168 except TypeError: 169 raise ValidationError, _("No file was submitted. Check the encoding type on the form.") 170 try: 171 # load() is the only method that can spot a truncated JPEG, 172 # but it cannot be called sanely after verify() 173 trial_image = Image.open(StringIO(content)) 174 trial_image.load() 175 # verify() is the only method that can spot a corrupt PNG, 176 # but it must be called immediately after the constructor 177 trial_image = Image.open(StringIO(content)) 178 trial_image.verify() 179 except Exception: # Python Imaging Library doesn't recognize it as an image 180 raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.") 181 182 def isValidImageURL(field_data, all_data): 183 uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png')) 184 try: 185 uc(field_data, all_data) 186 except URLMimeTypeCheck.InvalidContentType: 187 raise ValidationError, _("The URL %s does not point to a valid image.") % field_data 188 189 def isValidPhone(field_data, all_data): 190 if not phone_re.search(field_data): 191 raise ValidationError, _('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data 192 193 def isValidQuicktimeVideoURL(field_data, all_data): 194 "Checks that the given URL is a video that can be played by QuickTime (qt, mpeg)" 195 uc = URLMimeTypeCheck(('video/quicktime', 'video/mpeg',)) 196 try: 197 uc(field_data, all_data) 198 except URLMimeTypeCheck.InvalidContentType: 199 raise ValidationError, _("The URL %s does not point to a valid QuickTime video.") % field_data 200 201 def isValidURL(field_data, all_data): 202 if not url_re.search(field_data): 203 raise ValidationError, _("A valid URL is required.") 204 205 def isValidHTML(field_data, all_data): 206 import urllib, urllib2 207 try: 208 u = urllib2.urlopen('http://validator.w3.org/check', urllib.urlencode({'fragment': field_data, 'output': 'xml'})) 209 except: 210 # Validator or Internet connection is unavailable. Fail silently. 211 return 212 html_is_valid = (u.headers.get('x-w3c-validator-status', 'Invalid') == 'Valid') 213 if html_is_valid: 214 return 215 from xml.dom.minidom import parseString 216 error_messages = [e.firstChild.wholeText for e in parseString(u.read()).getElementsByTagName('messages')[0].getElementsByTagName('msg')] 217 raise ValidationError, _("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages) 218 219 def isWellFormedXml(field_data, all_data): 220 from xml.dom.minidom import parseString 221 try: 222 parseString(field_data) 223 except Exception, e: # Naked except because we're not sure what will be thrown 224 raise ValidationError, _("Badly formed XML: %s") % str(e) 225 226 def isWellFormedXmlFragment(field_data, all_data): 227 isWellFormedXml('<root>%s</root>' % field_data, all_data) 228 229 def isExistingURL(field_data, all_data): 230 try: 231 headers = { 232 "Accept" : "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", 233 "Accept-Language" : "en-us,en;q=0.5", 234 "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7", 235 "Connection" : "close", 236 "User-Agent": settings.URL_VALIDATOR_USER_AGENT 237 } 238 req = urllib2.Request(field_data,None, headers) 239 u = urllib2.urlopen(req) 240 except ValueError: 241 raise ValidationError, _("Invalid URL: %s") % field_data 242 except urllib2.HTTPError, e: 243 # 401s are valid; they just mean authorization is required. 244 # 301 and 302 are redirects; they just mean look somewhere else. 245 if str(e.code) not in ('401','301','302'): 246 raise ValidationError, _("The URL %s is a broken link.") % field_data 247 except: # urllib2.URLError, httplib.InvalidURL, etc. 248 raise ValidationError, _("The URL %s is a broken link.") % field_data 249 250 def isValidUSState(field_data, all_data): 251 "Checks that the given string is a valid two-letter U.S. state abbreviation" 252 states = ['AA', 'AE', 'AK', 'AL', 'AP', 'AR', 'AS', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'FM', 'GA', 'GU', 'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME', 'MH', 'MI', 'MN', 'MO', 'MP', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'PR', 'PW', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VA', 'VI', 'VT', 'WA', 'WI', 'WV', 'WY'] 253 if field_data.upper() not in states: 254 raise ValidationError, _("Enter a valid U.S. state abbreviation.") 255 256 def hasNoProfanities(field_data, all_data): 257 """ 258 Checks that the given string has no profanities in it. This does a simple 259 check for whether each profanity exists within the string, so 'fuck' will 260 catch 'motherfucker' as well. Raises a ValidationError such as: 261 Watch your mouth! The words "f--k" and "s--t" are not allowed here. 262 """ 263 field_data = field_data.lower() # normalize 264 words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data] 265 if words_seen: 266 from django.utils.text import get_text_list 267 plural = len(words_seen) 268 raise ValidationError, ungettext("Watch your mouth! The word %s is not allowed here.", 269 "Watch your mouth! The words %s are not allowed here.", plural) % \ 270 get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], _('and')) 271 272 class AlwaysMatchesOtherField(object): 273 def __init__(self, other_field_name, error_message=None): 274 self.other = other_field_name 275 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must match the '%s' field."), self.other) 276 self.always_test = True 277 278 def __call__(self, field_data, all_data): 279 if field_data != all_data[self.other]: 280 raise ValidationError, self.error_message 281 282 class ValidateIfOtherFieldEquals(object): 283 def __init__(self, other_field, other_value, validator_list): 284 self.other_field, self.other_value = other_field, other_value 285 self.validator_list = validator_list 286 self.always_test = True 287 288 def __call__(self, field_data, all_data): 289 if self.other_field in all_data and all_data[self.other_field] == self.other_value: 290 for v in self.validator_list: 291 v(field_data, all_data) 292 293 class RequiredIfOtherFieldNotGiven(object): 294 def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter something for at least one field.")): 295 self.other, self.error_message = other_field_name, error_message 296 self.always_test = True 297 298 def __call__(self, field_data, all_data): 299 if not all_data.get(self.other, False) and not field_data: 300 raise ValidationError, self.error_message 301 302 class RequiredIfOtherFieldsGiven(object): 303 def __init__(self, other_field_names, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")): 304 self.other, self.error_message = other_field_names, error_message 305 self.always_test = True 306 307 def __call__(self, field_data, all_data): 308 for field in self.other: 309 if all_data.get(field, False) and not field_data: 310 raise ValidationError, self.error_message 311 312 class RequiredIfOtherFieldGiven(RequiredIfOtherFieldsGiven): 313 "Like RequiredIfOtherFieldsGiven, but takes a single field name instead of a list." 314 def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")): 315 RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message) 316 317 class RequiredIfOtherFieldEquals(object): 318 def __init__(self, other_field, other_value, error_message=None, other_label=None): 319 self.other_field = other_field 320 self.other_value = other_value 321 other_label = other_label or other_value 322 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is %(value)s"), { 323 'field': other_field, 'value': other_label}) 324 self.always_test = True 325 326 def __call__(self, field_data, all_data): 327 if self.other_field in all_data and all_data[self.other_field] == self.other_value and not field_data: 328 raise ValidationError(self.error_message) 329 330 class RequiredIfOtherFieldDoesNotEqual(object): 331 def __init__(self, other_field, other_value, other_label=None, error_message=None): 332 self.other_field = other_field 333 self.other_value = other_value 334 other_label = other_label or other_value 335 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is not %(value)s"), { 336 'field': other_field, 'value': other_label}) 337 self.always_test = True 338 339 def __call__(self, field_data, all_data): 340 if self.other_field in all_data and all_data[self.other_field] != self.other_value and not field_data: 341 raise ValidationError(self.error_message) 342 343 class IsLessThanOtherField(object): 344 def __init__(self, other_field_name, error_message): 345 self.other, self.error_message = other_field_name, error_message 346 347 def __call__(self, field_data, all_data): 348 if field_data > all_data[self.other]: 349 raise ValidationError, self.error_message 350 351 class UniqueAmongstFieldsWithPrefix(object): 352 def __init__(self, field_name, prefix, error_message): 353 self.field_name, self.prefix = field_name, prefix 354 self.error_message = error_message or ugettext_lazy("Duplicate values are not allowed.") 355 356 def __call__(self, field_data, all_data): 357 for field_name, value in all_data.items(): 358 if field_name != self.field_name and value == field_data: 359 raise ValidationError, self.error_message 360 361 class NumberIsInRange(object): 362 """ 363 Validator that tests if a value is in a range (inclusive). 364 """ 365 def __init__(self, lower=None, upper=None, error_message=''): 366 self.lower, self.upper = lower, upper 367 if not error_message: 368 if lower and upper: 369 self.error_message = _("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper} 370 elif lower: 371 self.error_message = _("This value must be at least %s.") % lower 372 elif upper: 373 self.error_message = _("This value must be no more than %s.") % upper 374 else: 375 self.error_message = error_message 376 377 def __call__(self, field_data, all_data): 378 # Try to make the value numeric. If this fails, we assume another 379 # validator will catch the problem. 380 try: 381 val = float(field_data) 382 except ValueError: 383 return 384 385 # Now validate 386 if self.lower and self.upper and (val < self.lower or val > self.upper): 387 raise ValidationError(self.error_message) 388 elif self.lower and val < self.lower: 389 raise ValidationError(self.error_message) 390 elif self.upper and val > self.upper: 391 raise ValidationError(self.error_message) 392 393 class IsAPowerOf(object): 394 """ 395 Usage: If you create an instance of the IsPowerOf validator: 396 v = IsAPowerOf(2) 397 398 The following calls will succeed: 399 v(4, None) 400 v(8, None) 401 v(16, None) 402 403 But this call: 404 v(17, None) 405 will raise "django.core.validators.ValidationError: ['This value must be a power of 2.']" 406 """ 407 def __init__(self, power_of): 408 self.power_of = power_of 409 410 def __call__(self, field_data, all_data): 411 from math import log 412 val = log(int(field_data)) / log(self.power_of) 413 if val != int(val): 414 raise ValidationError, _("This value must be a power of %s.") % self.power_of 415 416 class IsValidDecimal(object): 417 def __init__(self, max_digits, decimal_places): 418 self.max_digits, self.decimal_places = max_digits, decimal_places 419 420 def __call__(self, field_data, all_data): 421 try: 422 val = Decimal(field_data) 423 except DecimalException: 424 raise ValidationError, _("Please enter a valid decimal number.") 425 426 pieces = str(val).lstrip("-").split('.') 427 decimals = (len(pieces) == 2) and len(pieces[1]) or 0 428 digits = len(pieces[0]) 429 430 if digits + decimals > self.max_digits: 431 raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.", 432 "Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits 433 if digits > (self.max_digits - self.decimal_places): 434 raise ValidationError, ungettext( "Please enter a valid decimal number with a whole part of at most %s digit.", 435 "Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places) 436 if decimals > self.decimal_places: 437 raise ValidationError, ungettext("Please enter a valid decimal number with at most %s decimal place.", 438 "Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places 439 440 def isValidFloat(field_data, all_data): 441 data = smart_str(field_data) 442 try: 443 float(data) 444 except ValueError: 445 raise ValidationError, _("Please enter a valid floating point number.") 446 447 class HasAllowableSize(object): 448 """ 449 Checks that the file-upload field data is a certain size. min_size and 450 max_size are measurements in bytes. 451 """ 452 def __init__(self, min_size=None, max_size=None, min_error_message=None, max_error_message=None): 453 self.min_size, self.max_size = min_size, max_size 454 self.min_error_message = min_error_message or lazy_inter(ugettext_lazy("Make sure your uploaded file is at least %s bytes big."), min_size) 455 self.max_error_message = max_error_message or lazy_inter(ugettext_lazy("Make sure your uploaded file is at most %s bytes big."), max_size) 456 457 def __call__(self, field_data, all_data): 458 try: 459 content = field_data['content'] 460 except TypeError: 461 raise ValidationError, ugettext_lazy("No file was submitted. Check the encoding type on the form.") 462 if self.min_size is not None and len(content) < self.min_size: 463 raise ValidationError, self.min_error_message 464 if self.max_size is not None and len(content) > self.max_size: 465 raise ValidationError, self.max_error_message 466 467 class MatchesRegularExpression(object): 468 """ 469 Checks that the field matches the given regular-expression. The regex 470 should be in string format, not already compiled. 471 """ 472 def __init__(self, regexp, error_message=ugettext_lazy("The format for this field is wrong.")): 473 self.regexp = re.compile(regexp) 474 self.error_message = error_message 475 476 def __call__(self, field_data, all_data): 477 if not self.regexp.search(field_data): 478 raise ValidationError(self.error_message) 479 480 class AnyValidator(object): 481 """ 482 This validator tries all given validators. If any one of them succeeds, 483 validation passes. If none of them succeeds, the given message is thrown 484 as a validation error. The message is rather unspecific, so it's best to 485 specify one on instantiation. 486 """ 487 def __init__(self, validator_list=None, error_message=ugettext_lazy("This field is invalid.")): 488 if validator_list is None: validator_list = [] 489 self.validator_list = validator_list 490 self.error_message = error_message 491 for v in validator_list: 492 if hasattr(v, 'always_test'): 493 self.always_test = True 494 495 def __call__(self, field_data, all_data): 496 for v in self.validator_list: 497 try: 498 v(field_data, all_data) 499 return 500 except ValidationError, e: 501 pass 502 raise ValidationError(self.error_message) 503 504 class URLMimeTypeCheck(object): 505 "Checks that the provided URL points to a document with a listed mime type" 506 class CouldNotRetrieve(ValidationError): 507 pass 508 class InvalidContentType(ValidationError): 509 pass 510 511 def __init__(self, mime_type_list): 512 self.mime_type_list = mime_type_list 513 514 def __call__(self, field_data, all_data): 515 import urllib2 516 try: 517 isValidURL(field_data, all_data) 518 except ValidationError: 519 raise 520 try: 521 info = urllib2.urlopen(field_data).info() 522 except (urllib2.HTTPError, urllib2.URLError): 523 raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data 524 content_type = info['content-type'] 525 if content_type not in self.mime_type_list: 526 raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % { 527 'url': field_data, 'contenttype': content_type} 528 529 class RelaxNGCompact(object): 530 "Validate against a Relax NG compact schema" 531 def __init__(self, schema_path, additional_root_element=None): 532 self.schema_path = schema_path 533 self.additional_root_element = additional_root_element 534 535 def __call__(self, field_data, all_data): 536 import os, tempfile 537 if self.additional_root_element: 538 field_data = '<%(are)s>%(data)s\n</%(are)s>' % { 539 'are': self.additional_root_element, 540 'data': field_data 541 } 542 filename = tempfile.mktemp() # Insecure, but nothing else worked 543 fp = open(filename, 'w') 544 fp.write(field_data) 545 fp.close() 546 if not os.path.exists(settings.JING_PATH): 547 raise Exception, "%s not found!" % settings.JING_PATH 548 p = os.popen('%s -c %s %s' % (settings.JING_PATH, self.schema_path, filename)) 549 errors = [line.strip() for line in p.readlines()] 550 p.close() 551 os.unlink(filename) 552 display_errors = [] 553 lines = field_data.split('\n') 554 for error in errors: 555 ignored, line, level, message = error.split(':', 3) 556 # Scrape the Jing error messages to reword them more nicely. 557 m = re.search(r'Expected "(.*?)" to terminate element starting on line (\d+)', message) 558 if m: 559 display_errors.append(_('Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "%(start)s".)') % \ 560 {'tag':m.group(1).replace('/', ''), 'line':m.group(2), 'start':lines[int(m.group(2)) - 1][:30]}) 561 continue 562 if message.strip() == 'text not allowed here': 563 display_errors.append(_('Some text starting on line %(line)s is not allowed in that context. (Line starts with "%(start)s".)') % \ 564 {'line':line, 'start':lines[int(line) - 1][:30]}) 565 continue 566 m = re.search(r'\s*attribute "(.*?)" not allowed at this point; ignored', message) 567 if m: 568 display_errors.append(_('"%(attr)s" on line %(line)s is an invalid attribute. (Line starts with "%(start)s".)') % \ 569 {'attr':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 570 continue 571 m = re.search(r'\s*unknown element "(.*?)"', message) 572 if m: 573 display_errors.append(_('"<%(tag)s>" on line %(line)s is an invalid tag. (Line starts with "%(start)s".)') % \ 574 {'tag':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 575 continue 576 if message.strip() == 'required attributes missing': 577 display_errors.append(_('A tag on line %(line)s is missing one or more required attributes. (Line starts with "%(start)s".)') % \ 578 {'line':line, 'start':lines[int(line) - 1][:30]}) 579 continue 580 m = re.search(r'\s*bad value for attribute "(.*?)"', message) 581 if m: 582 display_errors.append(_('The "%(attr)s" attribute on line %(line)s has an invalid value. (Line starts with "%(start)s".)') % \ 583 {'attr':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 584 continue 585 # Failing all those checks, use the default error message. 586 display_error = 'Line %s: %s [%s]' % (line, message, level.strip()) 587 display_errors.append(display_error) 588 if len(display_errors) > 0: 589 raise ValidationError, display_errors -
tests/modeltests/manipulators/models.py
diff --git a/tests/modeltests/manipulators/models.py b/tests/modeltests/manipulators/models.py index 3e52e33..64cfbd3 100644
a b True 99 99 datetime.date(2005, 2, 13) 100 100 101 101 # Test isValidFloat Unicode coercion 102 >>> from django. core.validators import isValidFloat, ValidationError102 >>> from django.oldforms.validators import isValidFloat, ValidationError 103 103 >>> try: isValidFloat(u"ä", None) 104 104 ... except ValidationError: pass 105 105 """} -
tests/modeltests/model_forms/models.py
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index 470312f..864d3ab 100644
a b Create a new article, with categories, via the form. 478 478 ... model = Article 479 479 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01', 480 480 ... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) 481 >>> f.is_valid() 482 True 481 483 >>> new_art = f.save() 482 484 >>> new_art.id 483 485 2 … … ValidationError: [u'Select a valid choice. 100 is not one of the available choic 705 707 >>> f.clean('hello') 706 708 Traceback (most recent call last): 707 709 ... 708 ValidationError: [u'Enter a list of values.']710 TypeCoersionError: [u'Enter a list of values.'] 709 711 710 712 # Add a Category object *after* the ModelMultipleChoiceField has already been 711 713 # instantiated. This proves clean() checks the database during clean() rather … … u'...test2.txt' 829 831 >>> instance.delete() 830 832 831 833 # Test the non-required FileField 832 834 # It should fail since the field IS required on the model 833 835 >>> f = TextFileForm(data={'description': u'Assistance'}) 834 836 >>> f.fields['file'].required = False 835 837 >>> f.is_valid() 836 True 837 >>> instance = f.save() 838 >>> instance.file 839 '' 838 False 839 >>> f.errors 840 {'file': [u'This field is required.']} 840 841 841 842 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test3.txt', 'content': 'hello world'}}, instance=instance) 842 843 >>> f.is_valid() … … u'...test2.png' 899 900 >>> f = ImageFileForm(data={'description': u'Test'}) 900 901 >>> f.fields['image'].required = False 901 902 >>> f.is_valid() 902 True903 >>> instance = f.save()904 >>> instance.image 905 '' 903 False 904 >>> f.errors 905 {'image': [u'This field is required.']} 906 906 907 907 908 >>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': {'filename': 'test3.png', 'content': image_data}}, instance=instance) 908 909 >>> f.is_valid() -
tests/modeltests/validation/models.py
diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py index 63f9f7a..13416db 100644
a b class Person(models.Model): 15 15 name = models.CharField(max_length=20) 16 16 birthdate = models.DateField() 17 17 favorite_moment = models.DateTimeField() 18 email = models.EmailField() 19 18 email = models.EmailField(unique=True) 19 20 class Meta: 21 unique_together = (('name', 'is_child'),) 20 22 def __unicode__(self): 21 23 return self.name 22 24 … … __test__ = {'API_TESTS':""" 30 32 ... 'favorite_moment': datetime.datetime(2002, 4, 3, 13, 23), 31 33 ... 'email': 'john@example.com' 32 34 ... } 33 >>> p = Person(**valid_params) 35 >>> p = Person(**dict(valid_params, email='john@e.com', name='Jack')) 36 >>> p.validate() 37 >>> p.save() 38 39 >>> p = Person(**dict(valid_params, email='john@e.com')) 34 40 >>> p.validate() 35 {} 41 Traceback (most recent call last): 42 ... 43 ValidationError: {'email': [u'This field must be unique']} 36 44 37 >>> p = Person(**dict(valid_params, id='23' ))45 >>> p = Person(**dict(valid_params, id='23', name='Jack')) 38 46 >>> p.validate() 39 {} 47 Traceback (most recent call last): 48 ... 49 ValidationError: {'__all__': u'Fields name, is_child must be unique.'} 40 50 >>> p.id 41 23 51 '23' 42 52 43 >>> p = Person(**dict(valid_params, id='foo')) 44 >>> p.validate()['id'] 45 [u'This value must be an integer.'] 53 >>> p = Person(**dict(valid_params, email='john@e.com', id='foo')) 54 >>> p.validate() 55 Traceback (most recent call last): 56 ... 57 ValidationError: {'id': [u'This value must be an integer.'], 'email': [u'This field must be unique']} 46 58 47 59 >>> p = Person(**dict(valid_params, id=None)) 48 60 >>> p.validate() 49 {}50 61 >>> repr(p.id) 51 62 'None' 52 63 53 64 >>> p = Person(**dict(valid_params, is_child='t')) 54 65 >>> p.validate() 55 {}56 66 >>> p.is_child 57 True 67 't' 58 68 59 69 >>> p = Person(**dict(valid_params, is_child='f')) 60 70 >>> p.validate() 61 {}62 >>> p.is_child63 False64 71 65 72 >>> p = Person(**dict(valid_params, is_child=True)) 66 73 >>> p.validate() 67 {}68 74 >>> p.is_child 69 75 True 70 76 71 77 >>> p = Person(**dict(valid_params, is_child=False)) 72 78 >>> p.validate() 73 {}74 79 >>> p.is_child 75 80 False 76 81 77 82 >>> p = Person(**dict(valid_params, is_child='foo')) 78 >>> p.validate()['is_child'] 79 [u'This value must be either True or False.'] 83 >>> p.validate() 84 Traceback (most recent call last): 85 ... 86 ValidationError: {'is_child': [u'This value must be either True or False.']} 80 87 81 88 >>> p = Person(**dict(valid_params, name=u'Jose')) 82 89 >>> p.validate() 83 {}84 90 >>> p.name 85 91 u'Jose' 86 92 87 93 >>> p = Person(**dict(valid_params, name=227)) 88 94 >>> p.validate() 89 {}90 >>> p.name91 u'227'92 95 93 96 >>> p = Person(**dict(valid_params, birthdate=datetime.date(2000, 5, 3))) 94 97 >>> p.validate() 95 {}96 98 >>> p.birthdate 97 99 datetime.date(2000, 5, 3) 98 100 99 101 >>> p = Person(**dict(valid_params, birthdate=datetime.datetime(2000, 5, 3))) 100 102 >>> p.validate() 101 {}102 103 >>> p.birthdate 103 datetime.date (2000, 5, 3)104 datetime.datetime(2000, 5, 3, 0, 0) 104 105 105 106 >>> p = Person(**dict(valid_params, birthdate='2000-05-03')) 106 107 >>> p.validate() 107 {}108 108 >>> p.birthdate 109 datetime.date(2000, 5, 3) 109 '2000-05-03' 110 110 111 111 >>> p = Person(**dict(valid_params, birthdate='2000-5-3')) 112 112 >>> p.validate() 113 {}114 113 >>> p.birthdate 115 datetime.date(2000, 5, 3) 114 '2000-5-3' 116 115 117 116 >>> p = Person(**dict(valid_params, birthdate='foo')) 118 >>> p.validate()['birthdate'] 119 [u'Enter a valid date in YYYY-MM-DD format.'] 117 >>> p.validate() 118 Traceback (most recent call last): 119 ... 120 ValidationError: {'birthdate': [u'Enter a valid date in YYYY-MM-DD format.']} 120 121 121 122 >>> p = Person(**dict(valid_params, favorite_moment=datetime.datetime(2002, 4, 3, 13, 23))) 122 123 >>> p.validate() 123 {}124 124 >>> p.favorite_moment 125 125 datetime.datetime(2002, 4, 3, 13, 23) 126 126 127 127 >>> p = Person(**dict(valid_params, favorite_moment=datetime.datetime(2002, 4, 3))) 128 128 >>> p.validate() 129 {}130 129 >>> p.favorite_moment 131 130 datetime.datetime(2002, 4, 3, 0, 0) 132 131 133 132 >>> p = Person(**dict(valid_params, email='john@example.com')) 134 133 >>> p.validate() 135 {}136 134 >>> p.email 137 135 'john@example.com' 138 136 139 137 >>> p = Person(**dict(valid_params, email=u'john@example.com')) 140 138 >>> p.validate() 141 {}142 139 >>> p.email 143 140 u'john@example.com' 144 141 145 142 >>> p = Person(**dict(valid_params, email=22)) 146 >>> p.validate()['email'] 147 [u'Enter a valid e-mail address.'] 143 >>> p.validate() 144 Traceback (most recent call last): 145 ... 146 ValidationError: {'email': [u'Enter a valid e-mail address.']} 148 147 149 148 # Make sure that Date and DateTime return validation errors and don't raise Python errors. 150 >>> p = Person(name='John Doe', is_child=True, email='abc@def.com') 151 >>> errors = p.validate() 152 >>> errors['favorite_moment'] 149 >>> from django.core.validation import ValidationError 150 >>> try: 151 ... Person(name='John Doe', is_child=True, email='abc@def.com').validate() 152 ... except ValidationError, e: 153 ... e.message_dict['favorite_moment'] 154 ... e.message_dict['birthdate'] 153 155 [u'This field is required.'] 154 >>> errors['birthdate']155 156 [u'This field is required.'] 156 157 157 158 """} -
new file tests/regressiontests/core/models.py
diff --git a/tests/regressiontests/core/__init__.py b/tests/regressiontests/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/regressiontests/core/models.py b/tests/regressiontests/core/models.py new file mode 100644 index 0000000..e5a7950
- + 1 # A models.py so that tests run. 2 -
new file tests/regressiontests/core/tests.py
diff --git a/tests/regressiontests/core/tests.py b/tests/regressiontests/core/tests.py new file mode 100644 index 0000000..adc72df
- + 1 tests = r""" 2 ################### 3 # ValidationError # 4 ################### 5 >>> from django.core.exceptions import ValidationError 6 >>> from django.utils.translation import ugettext_lazy 7 8 # Can take a string. 9 >>> print ValidationError("There was an error.").messages 10 <ul class="errorlist"><li>There was an error.</li></ul> 11 12 # Can take a unicode string. 13 >>> print ValidationError(u"Not \u03C0.").messages 14 <ul class="errorlist"><li>Not π.</li></ul> 15 16 # Can take a lazy string. 17 >>> print ValidationError(ugettext_lazy("Error.")).messages 18 <ul class="errorlist"><li>Error.</li></ul> 19 20 # Can take a list. 21 >>> print ValidationError(["Error one.", "Error two."]).messages 22 <ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul> 23 24 # Can take a mixture in a list. 25 >>> print ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages 26 <ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul> 27 28 >>> class VeryBadError: 29 ... def __unicode__(self): return u"A very bad error." 30 31 # Can take a non-string. 32 >>> print ValidationError(VeryBadError()).messages 33 <ul class="errorlist"><li>A very bad error.</li></ul> 34 """ 35 -
tests/regressiontests/forms/error_messages.py
diff --git a/tests/regressiontests/forms/error_messages.py b/tests/regressiontests/forms/error_messages.py index 9f972f5..d2e4662 100644
a b ValidationError: [u'REQUIRED'] 35 35 >>> f.clean('abc') 36 36 Traceback (most recent call last): 37 37 ... 38 ValidationError: [u'INVALID']38 TypeCoersionError: [u'INVALID'] 39 39 >>> f.clean('4') 40 40 Traceback (most recent call last): 41 41 ... … … ValidationError: [u'REQUIRED'] 59 59 >>> f.clean('abc') 60 60 Traceback (most recent call last): 61 61 ... 62 ValidationError: [u'INVALID']62 TypeCoersionError: [u'INVALID'] 63 63 >>> f.clean('4') 64 64 Traceback (most recent call last): 65 65 ... … … ValidationError: [u'REQUIRED'] 87 87 >>> f.clean('abc') 88 88 Traceback (most recent call last): 89 89 ... 90 ValidationError: [u'INVALID']90 TypeCoersionError: [u'INVALID'] 91 91 >>> f.clean('4') 92 92 Traceback (most recent call last): 93 93 ... … … ValidationError: [u'REQUIRED'] 121 121 >>> f.clean('abc') 122 122 Traceback (most recent call last): 123 123 ... 124 ValidationError: [u'INVALID']124 TypeCoersionError: [u'INVALID'] 125 125 126 126 # TimeField ################################################################### 127 127 … … ValidationError: [u'REQUIRED'] 135 135 >>> f.clean('abc') 136 136 Traceback (most recent call last): 137 137 ... 138 ValidationError: [u'INVALID']138 TypeCoersionError: [u'INVALID'] 139 139 140 140 # DateTimeField ############################################################### 141 141 … … ValidationError: [u'REQUIRED'] 149 149 >>> f.clean('abc') 150 150 Traceback (most recent call last): 151 151 ... 152 ValidationError: [u'INVALID']152 TypeCoersionError: [u'INVALID'] 153 153 154 154 # RegexField ################################################################## 155 155 … … ValidationError: [u'LENGTH 11, MAX LENGTH 10'] 203 203 204 204 >>> e = {'required': 'REQUIRED'} 205 205 >>> e['invalid'] = 'INVALID' 206 >>> e['missing'] = 'MISSING'207 206 >>> e['empty'] = 'EMPTY FILE' 208 207 >>> f = FileField(error_messages=e) 209 208 >>> f.clean('') … … ValidationError: [u'REQUIRED'] 213 212 >>> f.clean('abc') 214 213 Traceback (most recent call last): 215 214 ... 216 ValidationError: [u'INVALID']215 TypeCoersionError: [u'INVALID'] 217 216 >>> f.clean({}) 218 217 Traceback (most recent call last): 219 218 ... 220 ValidationError: [u' MISSING']219 ValidationError: [u'REQUIRED'] 221 220 >>> f.clean({'filename': 'name', 'content':''}) 222 221 Traceback (most recent call last): 223 222 ... … … ValidationError: [u'REQUIRED'] 278 277 >>> f.clean('b') 279 278 Traceback (most recent call last): 280 279 ... 281 ValidationError: [u'NOT A LIST']280 TypeCoersionError: [u'NOT A LIST'] 282 281 >>> f.clean(['b']) 283 282 Traceback (most recent call last): 284 283 ... … … ValidationError: [u'REQUIRED'] 352 351 >>> f.clean('3') 353 352 Traceback (most recent call last): 354 353 ... 355 ValidationError: [u'NOT A LIST OF VALUES']354 TypeCoersionError: [u'NOT A LIST OF VALUES'] 356 355 >>> f.clean(['4']) 357 356 Traceback (most recent call last): 358 357 ... -
tests/regressiontests/forms/extra.py
diff --git a/tests/regressiontests/forms/extra.py b/tests/regressiontests/forms/extra.py index a8b3697..7e381db 100644
a b u'sirrobin' 424 424 # Test overriding ErrorList in a form # 425 425 ####################################### 426 426 427 >>> from django. newforms.utilimport ErrorList427 >>> from django.core.validation import ErrorList 428 428 >>> class DivErrorList(ErrorList): 429 429 ... def __unicode__(self): 430 430 ... return self.as_divs() -
tests/regressiontests/forms/fields.py
diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py index 9421d8c..d4f7e1a 100644
a b Each Field's __init__() takes at least these parameters: 31 31 field name, if the Field is part of a Form. 32 32 initial -- A value to use in this Field's initial display. This value is 33 33 *not* used as a fallback if data isn't given. 34 validators -- Optional list of additional validator functions 34 35 35 36 Other than that, the Field subclasses have class-specific options for 36 37 __init__(). For example, CharField has a max_length option. … … u'1234567890' 103 104 >>> f.clean('1234567890a') 104 105 u'1234567890a' 105 106 107 # Custom validator functions ################################################## 108 109 >>> def validator(value): raise ValidationError('validator failed') 110 >>> f = CharField(min_length=10, validators=[validator]) 111 >>> f.clean('aa') 112 Traceback (most recent call last): 113 ... 114 ValidationError: [u'validator failed'] 115 116 >>> def validator2(value): raise ValidationError('validator2 failed') 117 >>> f = CharField(min_length=10, validators=[validator, validator, validator2]) 118 >>> f.clean('aa') 119 Traceback (most recent call last): 120 ... 121 ValidationError: [u'validator failed', u'validator failed', u'validator2 failed'] 122 123 >>> class MyCharField(CharField): 124 ... validators = [validator] 125 >>> f = MyCharField() 126 >>> f.clean('aa') 127 Traceback (most recent call last): 128 ... 129 ValidationError: [u'validator failed'] 130 106 131 # IntegerField ################################################################ 107 132 108 133 >>> f = IntegerField() … … True 123 148 >>> f.clean('a') 124 149 Traceback (most recent call last): 125 150 ... 126 ValidationError: [u'Enter a whole number.']151 TypeCoersionError: [u'Enter a whole number.'] 127 152 >>> f.clean(42) 128 153 42 129 154 >>> f.clean(3.14) 130 155 Traceback (most recent call last): 131 156 ... 132 ValidationError: [u'Enter a whole number.']157 TypeCoersionError: [u'Enter a whole number.'] 133 158 >>> f.clean('1 ') 134 159 1 135 160 >>> f.clean(' 1') … … ValidationError: [u'Enter a whole number.'] 139 164 >>> f.clean('1a') 140 165 Traceback (most recent call last): 141 166 ... 142 ValidationError: [u'Enter a whole number.']167 TypeCoersionError: [u'Enter a whole number.'] 143 168 144 169 >>> f = IntegerField(required=False) 145 170 >>> f.clean('') … … True 157 182 >>> f.clean('a') 158 183 Traceback (most recent call last): 159 184 ... 160 ValidationError: [u'Enter a whole number.']185 TypeCoersionError: [u'Enter a whole number.'] 161 186 >>> f.clean('1 ') 162 187 1 163 188 >>> f.clean(' 1') … … ValidationError: [u'Enter a whole number.'] 167 192 >>> f.clean('1a') 168 193 Traceback (most recent call last): 169 194 ... 170 ValidationError: [u'Enter a whole number.']195 TypeCoersionError: [u'Enter a whole number.'] 171 196 172 197 IntegerField accepts an optional max_value parameter: 173 198 >>> f = IntegerField(max_value=10) … … True 260 285 >>> f.clean('a') 261 286 Traceback (most recent call last): 262 287 ... 263 ValidationError: [u'Enter a number.']288 TypeCoersionError: [u'Enter a number.'] 264 289 >>> f.clean('1.0 ') 265 290 1.0 266 291 >>> f.clean(' 1.0') … … ValidationError: [u'Enter a number.'] 270 295 >>> f.clean('1.0a') 271 296 Traceback (most recent call last): 272 297 ... 273 ValidationError: [u'Enter a number.']298 TypeCoersionError: [u'Enter a number.'] 274 299 275 300 >>> f = FloatField(required=False) 276 301 >>> f.clean('') … … Decimal("3.14") 322 347 >>> f.clean('a') 323 348 Traceback (most recent call last): 324 349 ... 325 ValidationError: [u'Enter a number.']350 TypeCoersionError: [u'Enter a number.'] 326 351 >>> f.clean(u'łąść') 327 352 Traceback (most recent call last): 328 353 ... 329 ValidationError: [u'Enter a number.']354 TypeCoersionError: [u'Enter a number.'] 330 355 >>> f.clean('1.0 ') 331 356 Decimal("1.0") 332 357 >>> f.clean(' 1.0') … … Decimal("1.0") 336 361 >>> f.clean('1.0a') 337 362 Traceback (most recent call last): 338 363 ... 339 ValidationError: [u'Enter a number.']364 TypeCoersionError: [u'Enter a number.'] 340 365 >>> f.clean('123.45') 341 366 Traceback (most recent call last): 342 367 ... … … ValidationError: [u'Ensure that there are no more than 4 digits in total.'] 372 397 >>> f.clean('--0.12') 373 398 Traceback (most recent call last): 374 399 ... 375 ValidationError: [u'Enter a number.']400 TypeCoersionError: [u'Enter a number.'] 376 401 377 402 >>> f = DecimalField(max_digits=4, decimal_places=2, required=False) 378 403 >>> f.clean('') … … datetime.date(2006, 10, 25) 433 458 >>> f.clean('2006-4-31') 434 459 Traceback (most recent call last): 435 460 ... 436 ValidationError: [u'Enter a valid date.']461 TypeCoersionError: [u'Enter a valid date.'] 437 462 >>> f.clean('200a-10-25') 438 463 Traceback (most recent call last): 439 464 ... 440 ValidationError: [u'Enter a valid date.']465 TypeCoersionError: [u'Enter a valid date.'] 441 466 >>> f.clean('25/10/06') 442 467 Traceback (most recent call last): 443 468 ... 444 ValidationError: [u'Enter a valid date.']469 TypeCoersionError: [u'Enter a valid date.'] 445 470 >>> f.clean(None) 446 471 Traceback (most recent call last): 447 472 ... … … so the default formats won't work unless you specify them: 469 494 >>> f.clean('2006-10-25') 470 495 Traceback (most recent call last): 471 496 ... 472 ValidationError: [u'Enter a valid date.']497 TypeCoersionError: [u'Enter a valid date.'] 473 498 >>> f.clean('10/25/2006') 474 499 Traceback (most recent call last): 475 500 ... 476 ValidationError: [u'Enter a valid date.']501 TypeCoersionError: [u'Enter a valid date.'] 477 502 >>> f.clean('10/25/06') 478 503 Traceback (most recent call last): 479 504 ... 480 ValidationError: [u'Enter a valid date.']505 TypeCoersionError: [u'Enter a valid date.'] 481 506 482 507 # TimeField ################################################################### 483 508 … … datetime.time(14, 25, 59) 494 519 >>> f.clean('hello') 495 520 Traceback (most recent call last): 496 521 ... 497 ValidationError: [u'Enter a valid time.']522 TypeCoersionError: [u'Enter a valid time.'] 498 523 >>> f.clean('1:24 p.m.') 499 524 Traceback (most recent call last): 500 525 ... 501 ValidationError: [u'Enter a valid time.']526 TypeCoersionError: [u'Enter a valid time.'] 502 527 503 528 TimeField accepts an optional input_formats parameter: 504 529 >>> f = TimeField(input_formats=['%I:%M %p']) … … so the default formats won't work unless you specify them: 516 541 >>> f.clean('14:30:45') 517 542 Traceback (most recent call last): 518 543 ... 519 ValidationError: [u'Enter a valid time.']544 TypeCoersionError: [u'Enter a valid time.'] 520 545 521 546 # DateTimeField ############################################################### 522 547 … … datetime.datetime(2006, 10, 25, 0, 0) 557 582 >>> f.clean('hello') 558 583 Traceback (most recent call last): 559 584 ... 560 ValidationError: [u'Enter a valid date/time.']585 TypeCoersionError: [u'Enter a valid date/time.'] 561 586 >>> f.clean('2006-10-25 4:30 p.m.') 562 587 Traceback (most recent call last): 563 588 ... 564 ValidationError: [u'Enter a valid date/time.']589 TypeCoersionError: [u'Enter a valid date/time.'] 565 590 566 591 DateField accepts an optional input_formats parameter: 567 592 >>> f = DateTimeField(input_formats=['%Y %m %d %I:%M %p']) … … so the default formats won't work unless you specify them: 581 606 >>> f.clean('2006-10-25 14:30:45') 582 607 Traceback (most recent call last): 583 608 ... 584 ValidationError: [u'Enter a valid date/time.']609 TypeCoersionError: [u'Enter a valid date/time.'] 585 610 586 611 >>> f = DateTimeField(required=False) 587 612 >>> f.clean(None) … … ValidationError: [u'This field is required.'] 773 798 >>> f.clean({}) 774 799 Traceback (most recent call last): 775 800 ... 776 ValidationError: [u' No file was submitted.']801 ValidationError: [u'This field is required.'] 777 802 778 803 >>> f.clean({}, '') 779 804 Traceback (most recent call last): 780 805 ... 781 ValidationError: [u' No file was submitted.']806 ValidationError: [u'This field is required.'] 782 807 783 808 >>> f.clean({}, 'files/test3.pdf') 784 809 'files/test3.pdf' … … ValidationError: [u'No file was submitted.'] 786 811 >>> f.clean('some content that is not a file') 787 812 Traceback (most recent call last): 788 813 ... 789 ValidationError: [u'No file was submitted. Check the encoding type on the form.']814 TypeCoersionError: [u'No file was submitted. Check the encoding type on the form.'] 790 815 791 816 >>> f.clean({'filename': 'name', 'content': None}) 792 817 Traceback (most recent call last): … … ValidationError: [u'This field is required.'] 1051 1076 >>> f.clean('hello') 1052 1077 Traceback (most recent call last): 1053 1078 ... 1054 ValidationError: [u'Enter a list of values.']1079 TypeCoersionError: [u'Enter a list of values.'] 1055 1080 >>> f.clean([]) 1056 1081 Traceback (most recent call last): 1057 1082 ... … … ValidationError: [u'Select a valid choice. 3 is not one of the available choices 1083 1108 >>> f.clean('hello') 1084 1109 Traceback (most recent call last): 1085 1110 ... 1086 ValidationError: [u'Enter a list of values.']1111 TypeCoersionError: [u'Enter a list of values.'] 1087 1112 >>> f.clean([]) 1088 1113 [] 1089 1114 >>> f.clean(()) … … ValidationError: [u'This field is required.'] 1176 1201 >>> f.clean('hello') 1177 1202 Traceback (most recent call last): 1178 1203 ... 1179 ValidationError: [u'Enter a list of values.']1204 TypeCoersionError: [u'Enter a list of values.'] 1180 1205 >>> f.clean(['hello', 'there']) 1181 1206 Traceback (most recent call last): 1182 1207 ... … … datetime.datetime(2006, 1, 10, 7, 30) 1202 1227 >>> f.clean('hello') 1203 1228 Traceback (most recent call last): 1204 1229 ... 1205 ValidationError: [u'Enter a list of values.']1230 TypeCoersionError: [u'Enter a list of values.'] 1206 1231 >>> f.clean(['hello', 'there']) 1207 1232 Traceback (most recent call last): 1208 1233 ... -
tests/regressiontests/forms/localflavor/generic.py
diff --git a/tests/regressiontests/forms/localflavor/generic.py b/tests/regressiontests/forms/localflavor/generic.py index 0dbe30d..1c200d0 100644
a b datetime.date(2006, 10, 25) 38 38 >>> f.clean('2006-4-31') 39 39 Traceback (most recent call last): 40 40 ... 41 ValidationError: [u'Enter a valid date.']41 TypeCoersionError: [u'Enter a valid date.'] 42 42 >>> f.clean('200a-10-25') 43 43 Traceback (most recent call last): 44 44 ... 45 ValidationError: [u'Enter a valid date.']45 TypeCoersionError: [u'Enter a valid date.'] 46 46 >>> f.clean('10/25/06') 47 47 Traceback (most recent call last): 48 48 ... 49 ValidationError: [u'Enter a valid date.']49 TypeCoersionError: [u'Enter a valid date.'] 50 50 >>> f.clean(None) 51 51 Traceback (most recent call last): 52 52 ... … … so the default formats won't work unless you specify them: 74 74 >>> f.clean('2006-10-25') 75 75 Traceback (most recent call last): 76 76 ... 77 ValidationError: [u'Enter a valid date.']77 TypeCoersionError: [u'Enter a valid date.'] 78 78 >>> f.clean('25/10/2006') 79 79 Traceback (most recent call last): 80 80 ... 81 ValidationError: [u'Enter a valid date.']81 TypeCoersionError: [u'Enter a valid date.'] 82 82 >>> f.clean('25/10/06') 83 83 Traceback (most recent call last): 84 84 ... 85 ValidationError: [u'Enter a valid date.']85 TypeCoersionError: [u'Enter a valid date.'] 86 86 87 87 ## Generic DateTimeField ###################################################### 88 88 … … datetime.datetime(2006, 10, 25, 0, 0) 126 126 >>> f.clean('hello') 127 127 Traceback (most recent call last): 128 128 ... 129 ValidationError: [u'Enter a valid date/time.']129 TypeCoersionError: [u'Enter a valid date/time.'] 130 130 >>> f.clean('2006-10-25 4:30 p.m.') 131 131 Traceback (most recent call last): 132 132 ... 133 ValidationError: [u'Enter a valid date/time.']133 TypeCoersionError: [u'Enter a valid date/time.'] 134 134 135 135 DateField accepts an optional input_formats parameter: 136 136 >>> f = DateTimeField(input_formats=['%Y %m %d %I:%M %p']) … … so the default formats won't work unless you specify them: 150 150 >>> f.clean('2006-10-25 14:30:45') 151 151 Traceback (most recent call last): 152 152 ... 153 ValidationError: [u'Enter a valid date/time.']153 TypeCoersionError: [u'Enter a valid date/time.'] 154 154 155 155 >>> f = DateTimeField(required=False) 156 156 >>> f.clean(None) -
tests/regressiontests/forms/util.py
diff --git a/tests/regressiontests/forms/util.py b/tests/regressiontests/forms/util.py index bfaf73f..9933968 100644
a b Tests for newforms/util.py module. 5 5 6 6 tests = r""" 7 7 >>> from django.newforms.util import * 8 >>> from django.utils.translation import ugettext_lazy9 8 10 9 ########### 11 10 # flatatt # … … u' id="header"' 18 17 u' class="news" title="Read this"' 19 18 >>> flatatt({}) 20 19 u'' 21 22 ###################23 # ValidationError #24 ###################25 26 # Can take a string.27 >>> print ValidationError("There was an error.").messages28 <ul class="errorlist"><li>There was an error.</li></ul>29 30 # Can take a unicode string.31 >>> print ValidationError(u"Not \u03C0.").messages32 <ul class="errorlist"><li>Not π.</li></ul>33 34 # Can take a lazy string.35 >>> print ValidationError(ugettext_lazy("Error.")).messages36 <ul class="errorlist"><li>Error.</li></ul>37 38 # Can take a list.39 >>> print ValidationError(["Error one.", "Error two."]).messages40 <ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul>41 42 # Can take a mixture in a list.43 >>> print ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages44 <ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul>45 46 >>> class VeryBadError:47 ... def __unicode__(self): return u"A very bad error."48 49 # Can take a non-string.50 >>> print ValidationError(VeryBadError()).messages51 <ul class="errorlist"><li>A very bad error.</li></ul>52 20 """