Ticket #6845: 6845-against-7424.diff
File 6845-against-7424.diff, 136.5 KB (added by , 17 years ago) |
---|
-
AUTHORS
diff --git a/AUTHORS b/AUTHORS index 294ad18..e864b38 100644
a b answer newbie questions, and generally made Django that much better: 381 381 ymasuda@ethercube.com 382 382 Jarek Zgoda <jarek.zgoda@gmail.com> 383 383 Cheng Zhang 384 Honza Kral <Honza.Kral@gmail.com> 384 385 385 386 A big THANK YOU goes to: 386 387 -
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 c867065..ebe44bc 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 190ffbd..19e3a73 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 7 7 class FlatPage(models.Model): 8 url = models.CharField(_('URL'), max_length=100, validator _list=[validators.isAlphaNumericURL], db_index=True,8 url = models.CharField(_('URL'), max_length=100, validators=[validators.isAlphaNumericURL], db_index=True, 9 9 help_text=_("Example: '/about/contact/'. Make sure to have leading and trailing slashes.")) 10 10 title = models.CharField(_('title'), max_length=200) 11 11 content = models.TextField(_('content')) -
django/contrib/localflavor/br/forms.py
diff --git a/django/contrib/localflavor/br/forms.py b/django/contrib/localflavor/br/forms.py index aa7e3b2..ca9e61b 100644
a b class BRPhoneNumberField(Field): 31 31 } 32 32 33 33 def clean(self, value): 34 super(BRPhoneNumberField, self).clean(value)34 value = super(BRPhoneNumberField, self).clean(value) 35 35 if value in EMPTY_VALUES: 36 36 return u'' 37 value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))37 value = re.sub('(\(|\)|\s+)', '', value) 38 38 m = phone_digits_re.search(value) 39 39 if m: 40 40 return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) -
django/contrib/localflavor/fi/forms.py
diff --git a/django/contrib/localflavor/fi/forms.py b/django/contrib/localflavor/fi/forms.py index a0274da..c91db42 100644
a b class FISocialSecurityNumber(Field): 29 29 } 30 30 31 31 def clean(self, value): 32 super(FISocialSecurityNumber, self).clean(value) 33 if value in EMPTY_VALUES: 32 # changed not to throw UnicodeDecode error when passed invalid data 33 # I think this SHOULD call super.clean, which would mean ^^^ 34 if self.required and value in EMPTY_VALUES: 35 raise ValidationError(self.error_messages['required']) 36 elif value in EMPTY_VALUES: 34 37 return u'' 35 38 36 39 checkmarks = "0123456789ABCDEFHJKLMNPRSTUVWXY" -
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..4de7c98
- + 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 TypeCoercionError(ValidationError): 50 pass -
django/core/validators.py
diff --git a/django/core/validators.py b/django/core/validators.py index e728dbc..2703455 100644
a b 1 1 """ 2 2 A library of validators that return None and raise ValidationError when the 3 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), the7 validator will *always* be run, regardless of whether its associated8 form field is required.9 4 """ 10 5 11 import urllib212 6 import re 13 try: 14 from decimal import Decimal, DecimalException 15 except ImportError: 16 from django.utils._decimal import Decimal, DecimalException # Python 2.3 7 import urllib2 17 8 18 9 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 10 from django.utils.translation import ugettext as _ 11 from django.core.validation import ValidationError 12 13 def regexp_validator(regexp, message): 14 if isinstance(regexp, basestring): 15 regexp = re.compile(regexp) 16 17 def _regexp_validator(value): 18 if not regexp.search(value): 19 raise ValidationError, _(message) 20 return _regexp_validator 22 21 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 22 email_re = re.compile( 31 23 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom 32 24 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string 33 25 r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain 34 integer_re = re.compile(r'^-?\d+$') 35 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 phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE) 37 slug_re = re.compile(r'^[-\w]+$') 38 url_re = re.compile(r'^https?://\S+$') 26 validate_email = regexp_validator(email_re, 'Enter a valid e-mail address.') 39 27 40 lazy_inter = lazy(lambda a,b: force_unicode(a) % b, unicode) 28 validate_ip_address4 = regexp_validator( 29 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}$'), 30 "Please enter a valid IP address." 31 ) 41 32 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)] 33 validate_phone_number = regexp_validator( 34 re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE), 35 _('Phone numbers must be in XXX-XXX-XXXX format.') 36 ) 50 37 51 def __str__(self): 52 # This is needed because, without a __str__(), printing an exception 53 # instance would result in this: 54 # AttributeError: ValidationError instance has no attribute 'args' 55 # See http://www.python.org/doc/current/tut/node10.html#handling 56 return str(self.messages) 38 validate_slug = regexp_validator( 39 re.compile(r'^[-\w]+$'), 40 "This value must contain only letters, numbers, underscores or hyphens." 41 ) 57 42 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.") 43 _datere = r'\d{4}-\d{1,2}-\d{1,2}' 44 validate_ansi_date = regexp_validator( 45 re.compile('^%s$' % _datere), 46 _('Enter a valid date in YYYY-MM-DD format.') 47 ) 85 48 86 def isUpperCase(field_data, all_data): 87 if field_data.upper() != field_data: 88 raise ValidationError, _("Lowercase letters are not allowed here.") 49 _timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?' 50 validate_ansi_time = regexp_validator( 51 re.compile('^%s$' % _timere), 52 _('Enter a valid time in HH:MM format.') 53 ) 89 54 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.") 55 validate_ansi_datetime = regexp_validator( 56 re.compile('^%s %s$' % (_datere, _timere)), 57 _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 58 ) 96 59 97 def isCommaSeparatedEmailList(field_data, all_data):60 def validate_comma_separated_email_list(value): 98 61 """ 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 whitespace62 Checks that value is a string of e-mail addresses separated by commas. 63 Blank value values will not throw a validation error, and whitespace 101 64 is allowed around the commas. 102 65 """ 103 for supposed_email in field_data.split(','):66 for supposed_email in value.split(','): 104 67 try: 105 isValidEmail(supposed_email.strip(), '')68 validate_email(supposed_email.strip()) 106 69 except ValidationError: 107 70 raise ValidationError, _("Enter valid e-mail addresses separated by commas.") 108 71 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): 72 def validate_existing_url(value): 243 73 try: 244 74 headers = { 245 75 "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 78 "Connection" : "close", 249 79 "User-Agent": settings.URL_VALIDATOR_USER_AGENT 250 80 } 251 req = urllib2.Request( field_data,None, headers)81 req = urllib2.Request(value,None, headers) 252 82 u = urllib2.urlopen(req) 253 83 except ValueError: 254 raise ValidationError, _("Invalid URL: %s") % field_data84 raise ValidationError, _("Invalid URL: %s") % value 255 85 except urllib2.HTTPError, e: 256 86 # 401s are valid; they just mean authorization is required. 257 87 # 301 and 302 are redirects; they just mean look somewhere else. 258 88 if str(e.code) not in ('401','301','302'): 259 raise ValidationError, _("The URL %s is a broken link.") % field_data89 raise ValidationError, _("The URL %s is a broken link.") % value 260 90 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) 305 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_message 309 self.always_test = True 310 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_message 314 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_message 318 self.always_test = True 319 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_message 324 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_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 %(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 RequiredIfOtherFieldDoesNotEqual(object): 344 def __init__(self, other_field, other_value, other_label=None, error_message=None): 345 self.other_field = other_field 346 self.other_value = other_value 347 other_label = other_label or other_value 348 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 = True 351 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_message 359 360 def __call__(self, field_data, all_data): 361 if field_data > all_data[self.other]: 362 raise ValidationError, self.error_message 363 364 class UniqueAmongstFieldsWithPrefix(object): 365 def __init__(self, field_name, prefix, error_message): 366 self.field_name, self.prefix = field_name, prefix 367 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_message 373 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, upper 380 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.") % lower 385 elif upper: 386 self.error_message = _("This value must be no more than %s.") % upper 387 else: 388 self.error_message = error_message 389 390 def __call__(self, field_data, all_data): 391 # Try to make the value numeric. If this fails, we assume another 392 # validator will catch the problem. 393 try: 394 val = float(field_data) 395 except ValueError: 396 return 397 398 # Now validate 399 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_of 422 423 def __call__(self, field_data, all_data): 424 from math import log 425 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_of 428 429 class IsValidDecimal(object): 430 def __init__(self, max_digits, decimal_places): 431 self.max_digits, self.decimal_places = max_digits, decimal_places 432 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 0 441 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_digits 446 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_places 452 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 and 463 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_size 467 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_message 477 if self.max_size is not None and len(content) > self.max_size: 478 raise ValidationError, self.max_error_message 479 480 class MatchesRegularExpression(object): 481 """ 482 Checks that the field matches the given regular-expression. The regex 483 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_message 488 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 thrown 497 as a validation error. The message is rather unspecific, so it's best to 498 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_list 503 self.error_message = error_message 504 for v in validator_list: 505 if hasattr(v, 'always_test'): 506 self.always_test = True 507 508 def __call__(self, field_data, all_data): 509 for v in self.validator_list: 510 try: 511 v(field_data, all_data) 512 return 513 except ValidationError, e: 514 pass 515 raise ValidationError(self.error_message) 91 raise ValidationError, _("The URL %s is a broken link.") % value 516 92 517 93 class URLMimeTypeCheck(object): 518 94 "Checks that the provided URL points to a document with a listed mime type" … … class URLMimeTypeCheck(object): 524 100 def __init__(self, mime_type_list): 525 101 self.mime_type_list = mime_type_list 526 102 527 def __call__(self, field_data, all_data):528 import urllib2103 def __call__(self, value): 104 validate_existing_url(value) 529 105 try: 530 isValidURL(field_data, all_data) 531 except ValidationError: 532 raise 533 try: 534 info = urllib2.urlopen(field_data).info() 106 info = urllib2.urlopen(value).info() 535 107 except (urllib2.HTTPError, urllib2.URLError): 536 raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data108 raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % value 537 109 content_type = info['content-type'] 538 110 if content_type not in self.mime_type_list: 539 111 raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % { 540 'url': field_data, 'contenttype': content_type}112 'url': value, 'contenttype': content_type} 541 113 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_path 546 self.additional_root_element = additional_root_element 114 def validate_imaga_url(value): 115 uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png')) 116 try: 117 uc(value) 118 except URLMimeTypeCheck.InvalidContentType: 119 raise ValidationError, _("The URL %s does not point to a valid image.") % value 547 120 548 def __call__(self, field_data, all_data): 549 import os, tempfile 550 if self.additional_root_element: 551 field_data = '<%(are)s>%(data)s\n</%(are)s>' % { 552 'are': self.additional_root_element, 553 'data': field_data 554 } 555 filename = tempfile.mktemp() # Insecure, but nothing else worked 556 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_PATH 561 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 continue 575 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 continue 579 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 continue 584 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 continue 589 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 continue 593 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 continue 598 # 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 121 def validate_float(value): 122 data = smart_str(value) 123 try: 124 float(data) 125 except ValueError: 126 raise ValidationError, _("Please enter a valid floating point number.") -
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..225fa77 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 clean(self, new_data=None): 282 self.to_python() 283 self.validate(new_data) 284 285 def to_python(self): 286 error_dict = {} 287 for f in self._meta.fields: 288 try: 289 value = f.to_python(getattr(self, f.attname, f.get_default())) 290 setattr(self, f.attname, value) 291 except ValidationError, e: 292 error_dict[f.name] = e.messages 293 if error_dict: 294 raise ValidationError(error_dict) 295 296 def validate(self, new_data=None): 281 297 """ 282 298 First coerces all fields on this instance to their proper Python types. 283 299 Then runs validation on every field. Returns a dictionary of 284 300 field_name -> error_list. 285 301 """ 302 if new_data is not None: 303 def get_value(f): 304 if f.name in new_data: 305 return f.to_python(new_data[f.name]) 306 return getattr(self, f.attname, f.get_default()) 307 else: 308 get_value = lambda f: getattr(self, f.attname, f.get_default()) 286 309 error_dict = {} 287 invalid_python = {}288 310 for f in self._meta.fields: 289 311 try: 290 setattr(self, f.attname, f.to_python(getattr(self, f.attname, f.get_default()))) 291 except validators.ValidationError, e: 312 value = get_value(f) 313 f.validate(value, instance=self) 314 if hasattr(self, 'validate_%s' % f.name): 315 getattr(self, 'validate_%s' % f.name)(value) 316 except ValidationError, e: 292 317 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 318 319 for un_together in self._meta.unique_together: 320 lookup = {} 321 for name in un_together: 322 if name in error_dict: 323 break 324 f = self._meta.get_field(name) 325 lookup['%s__exact' % name] = get_value(f) 326 try: 327 qset = self.__class__._default_manager.all() 328 if self.pk: 329 qset = qset.exclude(pk=self.pk) 330 obj = qset.get(**lookup) 331 error_dict[NON_FIELD_ERRORS] = _('Fields %s must be unique.') % ', '.join(un_together) 332 except self.DoesNotExist: 333 pass 334 335 if error_dict: 336 raise ValidationError(error_dict) 301 337 302 338 def _collect_sub_objects(self, seen_objs): 303 339 """ -
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 eceb493..c7d9ab3 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..a7426f7 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, TypeCoercionError 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 if value in EMPTY_VALUES: 102 return None 103 return smart_unicode(value) 104 105 def validate(self, value): 106 if self.required and value in EMPTY_VALUES: 107 raise ValidationError(self.error_messages['required']) 108 elist = ErrorList() 109 for validator in self.validators: 110 try: 111 validator(value) 112 except ValidationError, e: 113 elist.extend(e.messages) 114 if elist: 115 raise ValidationError(elist) 116 97 117 def clean(self, value): 98 118 """ 99 119 Validates the given value and returns its "cleaned" value as an … … class Field(object): 101 121 102 122 Raises ValidationError for any errors. 103 123 """ 104 if self.required and value in EMPTY_VALUES:105 raise ValidationError(self.error_messages['required'])124 value = self.to_python(value) 125 self.validate(value) 106 126 return value 107 127 108 128 def widget_attrs(self, widget): … … class CharField(Field): 129 149 self.max_length, self.min_length = max_length, min_length 130 150 super(CharField, self).__init__(*args, **kwargs) 131 151 132 def clean(self, value): 133 "Validates max_length and min_length. Returns a Unicode object." 134 super(CharField, self).clean(value) 152 def to_python(self, value): 135 153 if value in EMPTY_VALUES: 136 154 return u'' 137 value = smart_unicode(value) 155 return smart_unicode(value) 156 157 def validate(self, value): 158 "Validates max_length and min_length. Returns a Unicode object." 159 super(CharField, self).validate(value) 138 160 value_length = len(value) 161 if value_length == 0 and not self.required: 162 return 139 163 if self.max_length is not None and value_length > self.max_length: 140 164 raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length}) 141 165 if self.min_length is not None and value_length < self.min_length: 142 166 raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length}) 143 return value144 167 145 168 def widget_attrs(self, widget): 146 169 if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)): … … class IntegerField(Field): 158 181 self.max_value, self.min_value = max_value, min_value 159 182 super(IntegerField, self).__init__(*args, **kwargs) 160 183 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) 184 def to_python(self, value): 167 185 if value in EMPTY_VALUES: 168 186 return None 169 187 try: 170 value = int(str(value))188 return int(smart_str(value)) 171 189 except (ValueError, TypeError): 172 raise ValidationError(self.error_messages['invalid']) 190 raise TypeCoercionError(self.error_messages['invalid']) 191 192 def validate(self, value): 193 """ 194 Validates that int() can be called on the input. Returns the result 195 of int(). Returns None for empty values. 196 """ 197 super(IntegerField, self).validate(value) 198 if value is None: return 173 199 if self.max_value is not None and value > self.max_value: 174 200 raise ValidationError(self.error_messages['max_value'] % self.max_value) 175 201 if self.min_value is not None and value < self.min_value: 176 202 raise ValidationError(self.error_messages['min_value'] % self.min_value) 177 return value178 203 179 204 class FloatField(Field): 180 205 default_error_messages = { … … class FloatField(Field): 187 212 self.max_value, self.min_value = max_value, min_value 188 213 Field.__init__(self, *args, **kwargs) 189 214 190 def clean(self, value):215 def to_python(self, value): 191 216 """ 192 217 Validates that float() can be called on the input. Returns a float. 193 218 Returns None for empty values. 194 219 """ 195 super(FloatField, self).clean(value) 196 if not self.required and value in EMPTY_VALUES: 220 if value in EMPTY_VALUES: 197 221 return None 198 222 try: 199 value =float(value)223 return float(value) 200 224 except (ValueError, TypeError): 201 raise ValidationError(self.error_messages['invalid']) 225 raise TypeCoercionError(self.error_messages['invalid']) 226 227 def validate(self, value): 228 super(FloatField, self).validate(value) 229 if value is None: return 202 230 if self.max_value is not None and value > self.max_value: 203 231 raise ValidationError(self.error_messages['max_value'] % self.max_value) 204 232 if self.min_value is not None and value < self.min_value: 205 233 raise ValidationError(self.error_messages['min_value'] % self.min_value) 206 return value207 234 208 235 class DecimalField(Field): 209 236 default_error_messages = { … … class DecimalField(Field): 220 247 self.max_digits, self.decimal_places = max_digits, decimal_places 221 248 Field.__init__(self, *args, **kwargs) 222 249 223 def clean(self, value):250 def to_python(self, value): 224 251 """ 225 252 Validates that the input is a decimal number. Returns a Decimal 226 253 instance. Returns None for empty values. Ensures that there are no more 227 254 than max_digits in the number, and no more than decimal_places digits 228 255 after the decimal point. 229 256 """ 230 super(DecimalField, self).clean(value) 231 if not self.required and value in EMPTY_VALUES: 257 if value in EMPTY_VALUES: 232 258 return None 233 259 value = smart_str(value).strip() 234 260 try: 235 value =Decimal(value)261 return Decimal(value) 236 262 except DecimalException: 237 raise ValidationError(self.error_messages['invalid']) 263 raise TypeCoercionError(self.error_messages['invalid']) 264 265 def validate(self, value): 266 super(DecimalField, self).validate(value) 267 if value is None: return 238 268 pieces = str(value).lstrip("-").split('.') 239 269 decimals = (len(pieces) == 2) and len(pieces[1]) or 0 240 270 digits = len(pieces[0]) … … class DecimalField(Field): 248 278 raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places) 249 279 if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places): 250 280 raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) 251 return value252 281 253 282 DEFAULT_DATE_INPUT_FORMATS = ( 254 283 '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' … … class DateField(Field): 267 296 super(DateField, self).__init__(*args, **kwargs) 268 297 self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS 269 298 270 def clean(self, value):299 def to_python(self, value): 271 300 """ 272 301 Validates that the input can be converted to a date. Returns a Python 273 302 datetime.date object. 274 303 """ 275 super(DateField, self).clean(value)276 304 if value in EMPTY_VALUES: 277 305 return None 278 306 if isinstance(value, datetime.datetime): … … class DateField(Field): 284 312 return datetime.date(*time.strptime(value, format)[:3]) 285 313 except ValueError: 286 314 continue 287 raise ValidationError(self.error_messages['invalid'])315 raise TypeCoercionError(self.error_messages['invalid']) 288 316 289 317 DEFAULT_TIME_INPUT_FORMATS = ( 290 318 '%H:%M:%S', # '14:30:59' … … class TimeField(Field): 300 328 super(TimeField, self).__init__(*args, **kwargs) 301 329 self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS 302 330 303 def clean(self, value):331 def to_python(self, value): 304 332 """ 305 333 Validates that the input can be converted to a time. Returns a Python 306 334 datetime.time object. 307 335 """ 308 super(TimeField, self).clean(value)309 336 if value in EMPTY_VALUES: 310 337 return None 311 338 if isinstance(value, datetime.time): … … class TimeField(Field): 315 342 return datetime.time(*time.strptime(value, format)[3:6]) 316 343 except ValueError: 317 344 continue 318 raise ValidationError(self.error_messages['invalid'])345 raise TypeCoercionError(self.error_messages['invalid']) 319 346 320 347 DEFAULT_DATETIME_INPUT_FORMATS = ( 321 348 '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' … … class DateTimeField(Field): 339 366 super(DateTimeField, self).__init__(*args, **kwargs) 340 367 self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS 341 368 342 def clean(self, value):369 def to_python(self, value): 343 370 """ 344 371 Validates that the input can be converted to a datetime. Returns a 345 372 Python datetime.datetime object. 346 373 """ 347 super(DateTimeField, self).clean(value)348 374 if value in EMPTY_VALUES: 349 375 return None 350 376 if isinstance(value, datetime.datetime): … … class DateTimeField(Field): 362 388 return datetime.datetime(*time.strptime(value, format)[:6]) 363 389 except ValueError: 364 390 continue 365 raise ValidationError(self.error_messages['invalid'])391 raise TypeCoercionError(self.error_messages['invalid']) 366 392 367 393 class RegexField(CharField): 368 394 def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs): … … class RegexField(CharField): 381 407 regex = re.compile(regex) 382 408 self.regex = regex 383 409 384 def clean(self, value):410 def validate(self, value): 385 411 """ 386 412 Validates that the input matches the regular expression. Returns a 387 413 Unicode object. 388 414 """ 389 value = super(RegexField, self).clean(value)390 if value == u'':391 return value415 super(RegexField, self).validate(value) 416 if value in EMPTY_VALUES: 417 return u'' 392 418 if not self.regex.search(value): 393 419 raise ValidationError(self.error_messages['invalid']) 394 return value395 420 396 421 email_re = re.compile( 397 422 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom … … class FileField(Field): 431 456 widget = FileInput 432 457 default_error_messages = { 433 458 'invalid': _(u"No file was submitted. Check the encoding type on the form."), 434 'missing': _(u"No file was submitted."),435 459 'empty': _(u"The submitted file is empty."), 436 460 } 437 461 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) 462 def to_python(self, data, initial=None): 443 463 if not self.required and data in EMPTY_VALUES: 444 464 return None 445 465 elif not data and initial: 446 466 return initial 467 elif not data: 468 return None 469 447 470 try: 448 471 f = UploadedFile(data['filename'], data['content']) 449 472 except TypeError: 450 raise ValidationError(self.error_messages['invalid'])473 raise TypeCoercionError(self.error_messages['invalid']) 451 474 except KeyError: 452 raise ValidationError(self.error_messages[' missing'])475 raise ValidationError(self.error_messages['required']) 453 476 if not f.content: 454 477 raise ValidationError(self.error_messages['empty']) 455 478 return f 456 479 480 def clean(self, data, initial=None): 481 "overriden clean to provide extra argument initial" 482 value = self.to_python(data, initial) 483 self.validate(value) 484 return value 485 457 486 class ImageField(FileField): 458 487 default_error_messages = { 459 488 'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."), 460 489 } 461 490 462 def clean(self, data, initial=None):491 def validate(self, value): 463 492 """ 464 493 Checks that the file-upload field data contains a valid image (GIF, JPG, 465 494 PNG, possibly others -- whatever the Python Imaging Library supports). 466 495 """ 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 496 super(ImageField, self).validate(value) 497 498 if value is None: 499 return 472 500 from PIL import Image 473 501 from cStringIO import StringIO 474 502 try: 475 503 # load() is the only method that can spot a truncated JPEG, 476 504 # but it cannot be called sanely after verify() 477 trial_image = Image.open(StringIO( f.content))505 trial_image = Image.open(StringIO(value.content)) 478 506 trial_image.load() 479 507 # verify() is the only method that can spot a corrupt PNG, 480 508 # but it must be called immediately after the constructor 481 trial_image = Image.open(StringIO( f.content))509 trial_image = Image.open(StringIO(value.content)) 482 510 trial_image.verify() 483 511 except Exception: # Python Imaging Library doesn't recognize it as an image 484 512 raise ValidationError(self.error_messages['invalid_image']) 485 return f486 513 487 514 url_re = re.compile( 488 515 r'^https?://' # http:// or https:// … … class URLField(RegexField): 505 532 self.verify_exists = verify_exists 506 533 self.user_agent = validator_user_agent 507 534 508 def clean(self, value):509 # If no URL scheme given, assume http://535 def to_python(self, value): 536 value = super(URLField, self).to_python(value) 510 537 if value and '://' not in value: 511 538 value = u'http://%s' % value 512 value = super(URLField, self).clean(value) 513 if value == u'': 514 return value 539 return value 540 541 def validate(self, value): 542 # If no URL scheme given, assume http:// 543 super(URLField, self).validate(value) 544 if value in EMPTY_VALUES: 545 return 515 546 if self.verify_exists: 516 547 import urllib2 517 548 from django.conf import settings … … class URLField(RegexField): 529 560 raise ValidationError(self.error_messages['invalid']) 530 561 except: # urllib2.URLError, httplib.InvalidURL, etc. 531 562 raise ValidationError(self.error_messages['invalid_link']) 532 return value533 563 534 564 class BooleanField(Field): 535 565 widget = CheckboxInput 536 566 537 def clean(self, value):567 def to_python(self, value): 538 568 """Returns a Python boolean object.""" 539 super(BooleanField, self).clean(value) 569 if self.required and value in EMPTY_VALUES: 570 raise ValidationError(self.error_messages['required']) 540 571 # Explicitly check for the string 'False', which is what a hidden field 541 572 # will submit for False. Because bool("True") == True, we don't need to 542 573 # handle that explicitly. … … class BooleanField(Field): 544 575 return False 545 576 return bool(value) 546 577 578 547 579 class NullBooleanField(BooleanField): 548 580 """ 549 581 A field whose valid values are None, True and False. Invalid values are 550 582 cleaned to None. 583 584 Note that validation doesn't apply here. 551 585 """ 552 586 widget = NullBooleanSelect 553 587 554 def clean(self, value):588 def to_python(self, value): 555 589 return {True: True, False: False}.get(value, None) 556 590 591 def validate(self, value): 592 pass 593 594 557 595 class ChoiceField(Field): 558 596 widget = Select 559 597 default_error_messages = { … … class ChoiceField(Field): 577 615 578 616 choices = property(_get_choices, _set_choices) 579 617 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 618 def validate(self, value): 619 super(ChoiceField, self).validate(value) 620 if value in EMPTY_VALUES and not self.required: 621 return u'' 590 622 valid_values = set([smart_unicode(k) for k, v in self.choices]) 591 623 if value not in valid_values: 592 624 raise ValidationError(self.error_messages['invalid_choice'] % {'value': value}) 593 return value594 625 595 626 class MultipleChoiceField(ChoiceField): 596 627 hidden_widget = MultipleHiddenInput … … class MultipleChoiceField(ChoiceField): 600 631 'invalid_list': _(u'Enter a list of values.'), 601 632 } 602 633 603 def clean(self, value):634 def to_python(self, value): 604 635 """ 605 636 Validates that the input is a list or tuple. 606 637 """ 607 if self.required and not value: 608 raise ValidationError(self.error_messages['required']) 609 elif not self.required and not value: 638 if not value: 610 639 return [] 611 640 if not isinstance(value, (list, tuple)): 612 raise ValidationError(self.error_messages['invalid_list']) 613 new_value = [smart_unicode(val) for val in value] 641 raise TypeCoercionError(self.error_messages['invalid_list']) 642 return [smart_unicode(val) for val in value] 643 644 def validate(self, value): 614 645 # Validate that each value in the value list is in self.choices. 646 if self.required and value == []: 647 raise ValidationError(self.error_messages['required']) 615 648 valid_values = set([smart_unicode(k) for k, v in self.choices]) 616 for val in new_value:649 for val in value: 617 650 if val not in valid_values: 618 651 raise ValidationError(self.error_messages['invalid_choice'] % {'value': val}) 619 return new_value620 652 621 653 class ComboField(Field): 622 654 """ … … class ComboField(Field): 631 663 f.required = False 632 664 self.fields = fields 633 665 634 def clean(self, value): 666 def to_python(self, value): 667 for field in self.fields: 668 value = field.to_python(value) 669 return value 670 671 def validate(self, value): 635 672 """ 636 673 Validates the given value against all of self.fields, which is a 637 674 list of Field instances. 638 675 """ 639 super(ComboField, self). clean(value)676 super(ComboField, self).validate(value) 640 677 for field in self.fields: 641 value = field.clean(value) 642 return value 678 field.validate(value) 643 679 644 680 class MultiValueField(Field): 645 681 """ … … class MultiValueField(Field): 671 707 f.required = False 672 708 self.fields = fields 673 709 674 def clean(self, value):710 def to_python(self, value): 675 711 """ 676 712 Validates every value in the given list. A value is validated against 677 713 the corresponding Field in self.fields. … … class MultiValueField(Field): 685 721 if not value or isinstance(value, (list, tuple)): 686 722 if not value or not [v for v in value if v not in EMPTY_VALUES]: 687 723 if self.required: 688 r aise ValidationError(self.error_messages['required'])724 return None 689 725 else: 690 726 return self.compress([]) 691 727 else: 692 raise ValidationError(self.error_messages['invalid']) 728 raise TypeCoercionError(self.error_messages['invalid']) 729 693 730 for i, field in enumerate(self.fields): 694 731 try: 695 732 field_value = value[i] -
django/newforms/forms.py
diff --git a/django/newforms/forms.py b/django/newforms/forms.py index 2c481e4..1c06f3c 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): 205 205 else: 206 206 value = field.clean(value) 207 207 self.cleaned_data[name] = value 208 # FIXME deprecated - keeping this here for backwards compatibility 208 209 if hasattr(self, 'clean_%s' % name): 209 210 value = getattr(self, 'clean_%s' % name)() 210 211 self.cleaned_data[name] = value 212 213 if hasattr(self, 'validate_%s' % name): 214 getattr(self, 'validate_%s' % name)(value) 211 215 except ValidationError, e: 212 216 self._errors[name] = e.messages 213 217 if name in self.cleaned_data: 214 218 del self.cleaned_data[name] 215 219 try: 216 self. cleaned_data = self.clean()220 self.validate() 217 221 except ValidationError, e: 218 self._errors[NON_FIELD_ERRORS] = e.messages 222 if hasattr(e, 'message_dict'): 223 for k, v in e.message_dict.items(): 224 self._errors.setdefault(k, []).extend(v) 225 else: 226 self._errors[NON_FIELD_ERRORS] = e.messages 219 227 if self._errors: 220 228 delattr(self, 'cleaned_data') 221 229 222 230 def clean(self): 223 231 """ 232 FIXME: deprecated, use validate() instead 233 224 234 Hook for doing any extra form-wide cleaning after Field.clean() been 225 235 called on every field. Any ValidationError raised by this method will 226 236 not be associated with a particular field; it will have a special-case … … class BaseForm(StrAndUnicode): 228 238 """ 229 239 return self.cleaned_data 230 240 241 def validate(self): 242 self.cleaned_data = self.clean() 243 231 244 def is_multipart(self): 232 245 """ 233 246 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..1c6e301 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, TypeCoercionError 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.clean(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 TypeCoercionError(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..58ca0cf 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 TypeCoercionError: [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..379647a 100644
a b 3 3 4 4 This is an experimental feature! 5 5 6 Each model instance has a validate() method that returns a dictionary of6 Each model instance has a clean() method that returns a dictionary of 7 7 validation errors in the instance's fields. This method has a side effect 8 8 of converting each field to its appropriate Python data type. 9 9 """ … … 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) 34 >>> p.validate() 35 {} 36 37 >>> p = Person(**dict(valid_params, id='23')) 38 >>> p.validate() 39 {} 35 >>> p = Person(**dict(valid_params, email='john@e.com', name='Jack')) 36 >>> p.clean() 37 >>> p.save() 38 39 >>> p = Person(**dict(valid_params, email='john@e.com')) 40 >>> p.clean() 41 Traceback (most recent call last): 42 ... 43 ValidationError: {'email': [u'This field must be unique']} 44 45 >>> p = Person(**dict(valid_params, id='23', name='Jack')) 46 >>> p.clean() 47 Traceback (most recent call last): 48 ... 49 ValidationError: {'__all__': u'Fields name, is_child must be unique.'} 40 50 >>> p.id 41 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 # when type coercion fails, no other validation is done 54 >>> p = Person(**dict(valid_params, email='john@e.com', id='foo')) 55 >>> p.clean() 56 Traceback (most recent call last): 57 ... 58 ValidationError: {'id': [u'This value must be an integer.']} 46 59 47 60 >>> p = Person(**dict(valid_params, id=None)) 48 >>> p.validate() 49 {} 61 >>> p.clean() 50 62 >>> repr(p.id) 51 63 'None' 52 64 53 65 >>> p = Person(**dict(valid_params, is_child='t')) 54 >>> p.validate() 55 {} 66 >>> p.clean() 56 67 >>> p.is_child 57 68 True 58 69 59 70 >>> p = Person(**dict(valid_params, is_child='f')) 60 >>> p.validate() 61 {} 71 >>> p.clean() 62 72 >>> p.is_child 63 73 False 64 74 65 75 >>> p = Person(**dict(valid_params, is_child=True)) 66 >>> p.validate() 67 {} 76 >>> p.clean() 68 77 >>> p.is_child 69 78 True 70 79 71 80 >>> p = Person(**dict(valid_params, is_child=False)) 72 >>> p.validate() 73 {} 81 >>> p.clean() 74 82 >>> p.is_child 75 83 False 76 84 77 85 >>> p = Person(**dict(valid_params, is_child='foo')) 78 >>> p.validate()['is_child'] 79 [u'This value must be either True or False.'] 86 >>> p.clean() 87 Traceback (most recent call last): 88 ... 89 ValidationError: {'is_child': [u'This value must be either True or False.']} 80 90 81 91 >>> p = Person(**dict(valid_params, name=u'Jose')) 82 >>> p.validate() 83 {} 92 >>> p.clean() 84 93 >>> p.name 85 94 u'Jose' 86 95 87 96 >>> p = Person(**dict(valid_params, name=227)) 88 >>> p.validate() 89 {} 97 >>> p.clean() 90 98 >>> p.name 91 99 u'227' 92 100 93 101 >>> p = Person(**dict(valid_params, birthdate=datetime.date(2000, 5, 3))) 94 >>> p.validate() 95 {} 102 >>> p.clean() 96 103 >>> p.birthdate 97 104 datetime.date(2000, 5, 3) 98 105 99 106 >>> p = Person(**dict(valid_params, birthdate=datetime.datetime(2000, 5, 3))) 100 >>> p.validate() 101 {} 107 >>> p.clean() 102 108 >>> p.birthdate 103 109 datetime.date(2000, 5, 3) 104 110 105 111 >>> p = Person(**dict(valid_params, birthdate='2000-05-03')) 106 >>> p.validate() 107 {} 112 >>> p.clean() 108 113 >>> p.birthdate 109 114 datetime.date(2000, 5, 3) 110 115 111 116 >>> p = Person(**dict(valid_params, birthdate='2000-5-3')) 112 >>> p.validate() 113 {} 117 >>> p.clean() 114 118 >>> p.birthdate 115 119 datetime.date(2000, 5, 3) 116 120 117 121 >>> p = Person(**dict(valid_params, birthdate='foo')) 118 >>> p.validate()['birthdate'] 119 [u'Enter a valid date in YYYY-MM-DD format.'] 122 >>> p.clean() 123 Traceback (most recent call last): 124 ... 125 ValidationError: {'birthdate': [u'Enter a valid date in YYYY-MM-DD format.']} 120 126 121 127 >>> p = Person(**dict(valid_params, favorite_moment=datetime.datetime(2002, 4, 3, 13, 23))) 122 >>> p.validate() 123 {} 128 >>> p.clean() 124 129 >>> p.favorite_moment 125 130 datetime.datetime(2002, 4, 3, 13, 23) 126 131 127 132 >>> p = Person(**dict(valid_params, favorite_moment=datetime.datetime(2002, 4, 3))) 128 >>> p.validate() 129 {} 133 >>> p.clean() 130 134 >>> p.favorite_moment 131 135 datetime.datetime(2002, 4, 3, 0, 0) 132 136 133 137 >>> p = Person(**dict(valid_params, email='john@example.com')) 134 >>> p.validate() 135 {} 138 >>> p.clean() 136 139 >>> p.email 137 140 'john@example.com' 138 141 139 142 >>> p = Person(**dict(valid_params, email=u'john@example.com')) 140 >>> p.validate() 141 {} 143 >>> p.clean() 142 144 >>> p.email 143 145 u'john@example.com' 144 146 145 147 >>> p = Person(**dict(valid_params, email=22)) 146 >>> p.validate()['email'] 147 [u'Enter a valid e-mail address.'] 148 >>> p.clean() 149 Traceback (most recent call last): 150 ... 151 ValidationError: {'email': [u'Enter a valid e-mail address.']} 148 152 149 153 # 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'] 154 >>> from django.core.validation import ValidationError 155 >>> try: 156 ... Person(name='John Doe', is_child=True, email='abc@def.com').clean() 157 ... except ValidationError, e: 158 ... e.message_dict['favorite_moment'] 159 ... e.message_dict['birthdate'] 153 160 [u'This field is required.'] 154 >>> errors['birthdate']155 161 [u'This field is required.'] 156 162 157 163 """} -
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..44f5a25 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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 f3b6a96..2fb77e7 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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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'Select a valid choice. That choice is not one of the availab 993 1018 994 1019 >>> f = ChoiceField(choices=[('1', '1'), ('2', '2')], required=False) 995 1020 >>> f.clean('') 996 u''997 1021 >>> f.clean(None) 998 u''999 1022 >>> f.clean(1) 1000 1023 u'1' 1001 1024 >>> f.clean('1') … … ValidationError: [u'This field is required.'] 1051 1074 >>> f.clean('hello') 1052 1075 Traceback (most recent call last): 1053 1076 ... 1054 ValidationError: [u'Enter a list of values.']1077 TypeCoercionError: [u'Enter a list of values.'] 1055 1078 >>> f.clean([]) 1056 1079 Traceback (most recent call last): 1057 1080 ... … … ValidationError: [u'Select a valid choice. 3 is not one of the available choices 1083 1106 >>> f.clean('hello') 1084 1107 Traceback (most recent call last): 1085 1108 ... 1086 ValidationError: [u'Enter a list of values.']1109 TypeCoercionError: [u'Enter a list of values.'] 1087 1110 >>> f.clean([]) 1088 1111 [] 1089 1112 >>> f.clean(()) … … ValidationError: [u'This field is required.'] 1186 1209 >>> f.clean('hello') 1187 1210 Traceback (most recent call last): 1188 1211 ... 1189 ValidationError: [u'Enter a list of values.']1212 TypeCoercionError: [u'Enter a list of values.'] 1190 1213 >>> f.clean(['hello', 'there']) 1191 1214 Traceback (most recent call last): 1192 1215 ... … … datetime.datetime(2006, 1, 10, 7, 30) 1212 1235 >>> f.clean('hello') 1213 1236 Traceback (most recent call last): 1214 1237 ... 1215 ValidationError: [u'Enter a list of values.']1238 TypeCoercionError: [u'Enter a list of values.'] 1216 1239 >>> f.clean(['hello', 'there']) 1217 1240 Traceback (most recent call last): 1218 1241 ... -
tests/regressiontests/forms/localflavor/br.py
diff --git a/tests/regressiontests/forms/localflavor/br.py b/tests/regressiontests/forms/localflavor/br.py index 757f382..94285c3 100644
a b Traceback (most recent call last): 85 85 ... 86 86 ValidationError: [u'Invalid CNPJ number.'] 87 87 >>> f.clean('64.132.916/0001-88') 88 '64.132.916/0001-88'88 u'64.132.916/0001-88' 89 89 >>> f.clean('64-132-916/0001-88') 90 '64-132-916/0001-88'90 u'64-132-916/0001-88' 91 91 >>> f.clean('64132916/0001-88') 92 '64132916/0001-88'92 u'64132916/0001-88' 93 93 >>> f.clean('64.132.916/0001-XX') 94 94 Traceback (most recent call last): 95 95 ... -
tests/regressiontests/forms/localflavor/generic.py
diff --git a/tests/regressiontests/forms/localflavor/generic.py b/tests/regressiontests/forms/localflavor/generic.py index 0dbe30d..cda4f89 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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 TypeCoercionError: [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 """