Ticket #6845: 6845-against-7877.2.patch
File 6845-against-7877.2.patch, 128.8 KB (added by , 16 years ago) |
---|
-
AUTHORS
diff --git a/AUTHORS b/AUTHORS index 7e91eda..62ea249 100644
a b answer newbie questions, and generally made Django that much better: 217 217 Igor Kolar <ike@email.si> 218 218 Gasper Koren 219 219 Martin Kosír <martin@martinkosir.net> 220 Honza Kral <Honza.Kral@gmail.com> 220 221 Meir Kriheli <http://mksoft.co.il/> 221 222 Bruce Kroeze <http://coderseye.com/> 222 223 krzysiek.pawlik@silvermedia.pl -
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/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/management/commands/createsuperuser.py
diff --git a/django/contrib/auth/management/commands/createsuperuser.py b/django/contrib/auth/management/commands/createsuperuser.py index 4299762..1e8a775 100644
a b class Command(BaseCommand): 39 39 if not RE_VALID_USERNAME.match(username): 40 40 raise CommandError("Invalid username. Use only letters, digits, and underscores") 41 41 try: 42 validators. isValidEmail(email, None)42 validators.validate_email(email) 43 43 except validators.ValidationError: 44 44 raise CommandError("Invalid email address.") 45 45 -
django/contrib/auth/models.py
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index 379a9f4..818e33a 100644
a b class User(models.Model): 135 135 136 136 Username and password are required. Other fields are optional. 137 137 """ 138 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)."))138 username = models.CharField(_('username'), max_length=30, unique=True, validator_list=[validators.validate_alpha_numeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores).")) 139 139 first_name = models.CharField(_('first name'), max_length=30, blank=True) 140 140 last_name = models.CharField(_('last name'), max_length=30, blank=True) 141 141 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 d61e9a3..e96c913 100644
a b 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, validator_list=[validators.validate_alpha_numeric], 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'), blank=True) -
django/contrib/localflavor/br/forms.py
diff --git a/django/contrib/localflavor/br/forms.py b/django/contrib/localflavor/br/forms.py index 81dcb82..f1162b7 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 e9e0fc1..d13c390 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 70def85..e5b9457 100644
a b 2 2 JP-specific Form helpers 3 3 """ 4 4 5 from django.core import validators6 from django.newforms import ValidationError7 5 from django.utils.translation import ugettext_lazy as _ 8 6 from django.newforms.fields import RegexField, Select 9 7 -
django/core/exceptions.py
diff --git a/django/core/exceptions.py b/django/core/exceptions.py index e5df8ca..fb6634f 100644
a b class FieldError(Exception): 32 32 """Some kind of problem with a model field.""" 33 33 pass 34 34 35 NON_FIELD_ERRORS = '__all__' 36 class ValidationError(Exception): 37 def __init__(self, message): 38 """ 39 ValidationError can be passed any object that can be printed (usually 40 a string) or a list of objects. 41 """ 42 from django.utils.encoding import force_unicode 43 if hasattr(message, '__iter__'): 44 self.messages = [force_unicode(msg) for msg in message] 45 else: 46 message = force_unicode(message) 47 self.messages = [message] 48 49 if isinstance(message, dict): 50 self.message_dict = message 51 52 def __str__(self): 53 # This is needed because, without a __str__(), printing an exception 54 # instance would result in this: 55 # AttributeError: ValidationError instance has no attribute 'args' 56 # See http://www.python.org/doc/current/tut/node10.html#handling 57 from django.utils.encoding import force_unicode 58 if hasattr(self, 'message_dict'): 59 return repr(self.message_dict) 60 return repr([force_unicode(e) for e in self.messages]) -
django/core/validators.py
diff --git a/django/core/validators.py b/django/core/validators.py index 3ef0ade..62af2eb 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.encoding import smart_str 11 from django.utils.translation import ugettext as _ 12 from django.core.exceptions import ValidationError 13 14 def regexp_validator(regexp, message_codes, message): 15 if isinstance(regexp, basestring): 16 regexp = re.compile(regexp) 17 18 def _regexp_validator(value, message_dict={}): 19 if not regexp.search(value): 20 for m in message_codes: 21 if m in message_dict: 22 mess = message_dict[m] 23 break 24 else: 25 mess = _(message) 26 27 raise ValidationError, mess 28 return _regexp_validator 22 29 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 30 email_re = re.compile( 31 31 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom 32 32 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string 33 33 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+$')39 40 lazy_inter = lazy(lambda a,b: force_unicode(a) % b, unicode)41 42 class ValidationError(Exception):43 def __init__(self, message):44 "ValidationError can be passed a string or a list."45 if isinstance(message, list):46 self.messages = [force_unicode(msg) for msg in message]47 else:48 assert isinstance(message, (basestring, Promise)), ("%s should be a string" % repr(message))49 self.messages = [force_unicode(message)]50 51 def __str__(self):52 # This is needed because, without a __str__(), printing an exception53 # instance would result in this:54 # AttributeError: ValidationError instance has no attribute 'args'55 # See http://www.python.org/doc/current/tut/node10.html#handling56 return str(self.messages)57 58 class CriticalValidationError(Exception):59 def __init__(self, message):60 "ValidationError can be passed a string or a list."61 if isinstance(message, list):62 self.messages = [force_unicode(msg) for msg in message]63 else:64 assert isinstance(message, (basestring, Promise)), ("'%s' should be a string" % message)65 self.messages = [force_unicode(message)]66 67 def __str__(self):68 return str(self.messages)69 70 def isAlphaNumeric(field_data, all_data):71 if not alnum_re.search(field_data):72 raise ValidationError, _("This value must contain only letters, numbers and underscores.")73 74 def isAlphaNumericURL(field_data, all_data):75 if not alnumurl_re.search(field_data):76 raise ValidationError, _("This value must contain only letters, numbers, underscores, dashes or slashes.")77 78 def isSlug(field_data, all_data):79 if not slug_re.search(field_data):80 raise ValidationError, _("This value must contain only letters, numbers, underscores or hyphens.")81 82 def isLowerCase(field_data, all_data):83 if field_data.lower() != field_data:84 raise ValidationError, _("Uppercase letters are not allowed here.")85 34 86 def isUpperCase(field_data, all_data): 87 if field_data.upper() != field_data: 88 raise ValidationError, _("Lowercase letters are not allowed here.") 35 validate_email = regexp_validator( 36 email_re, ('invalid_email','invalid',), 37 'Enter a valid e-mail address.' 38 ) 89 39 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.") 40 validate_alpha_numeric_URL = regexp_validator( 41 re.compile(r'^[-\w/]+$'), ('invalid',), 42 "This value must contain only letters, numbers, underscores, dashes or slashes." 43 ) 96 44 97 def isCommaSeparatedEmailList(field_data, all_data):98 """99 Checks that field_data is a string of e-mail addresses separated by commas.100 Blank field_data values will not throw a validation error, and whitespace101 is allowed around the commas.102 """103 for supposed_email in field_data.split(','):104 try:105 isValidEmail(supposed_email.strip(), '')106 except ValidationError:107 raise ValidationError, _("Enter valid e-mail addresses separated by commas.")108 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 45 113 def isNotEmpty(field_data, all_data): 114 if field_data.strip() == '': 115 raise ValidationError, _("Empty values are not allowed here.") 46 validate_alpha_numeric = regexp_validator( 47 re.compile(r'^\w+$'), ('invalid',), 48 "This value must contain only letters, numbers and underscores." 49 ) 116 50 117 def isOnlyDigits(field_data, all_data): 118 if not field_data.isdigit(): 119 raise ValidationError, _("Non-numeric characters aren't allowed here.") 51 validate_ip_address4 = regexp_validator( 52 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}$'), ('invalid',), 53 "Enter a valid IPv4 address." 54 ) 120 55 121 def isNotOnlyDigits(field_data, all_data): 122 if field_data.isdigit(): 123 raise ValidationError, _("This value can't be comprised solely of digits.") 56 validate_phone_number = regexp_validator( 57 re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE), ('invalid',), 58 'Phone numbers must be in XXX-XXX-XXXX format.' 59 ) 124 60 125 def isInteger(field_data, all_data): 126 # This differs from isOnlyDigits because this accepts the negative sign127 if not integer_re.search(field_data):128 raise ValidationError, _("Enter a whole number.")61 validate_slug = regexp_validator( 62 re.compile(r'^[-\w]+$'), ('invalid',), 63 "This value must contain only letters, numbers, underscores or hyphens." 64 ) 129 65 130 def isOnlyLetters(field_data, all_data): 131 if not field_data.isalpha(): 132 raise ValidationError, _("Only alphabetical characters are allowed here.") 66 _datere = r'\d{4}-\d{1,2}-\d{1,2}' 67 validate_ansi_date_format = regexp_validator( 68 re.compile('^%s$' % _datere), ('invalid',), 69 'Enter a valid date in YYYY-MM-DD format.' 70 ) 133 71 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 """ 72 _timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?' 73 validate_ansi_time = regexp_validator( 74 re.compile('^%s$' % _timere), ('invalid',), 75 'Enter a valid time in HH:MM format.' 76 ) 77 78 validate_ansi_datetime_format = regexp_validator( 79 re.compile('^%s %s$' % (_datere, _timere)), ('invalid',), 80 'Enter a valid date/time in YYYY-MM-DD HH:MM format.' 81 ) 82 83 validate_integer = regexp_validator( 84 re.compile(r'^-?\d+$'), ('invalid',), 85 "Enter a whole number." 86 ) 87 88 def validate_correct_ansi_date(value, message_dict={}): 140 89 from datetime import date 141 90 # Could use time.strptime here and catch errors, but datetime.date below 142 91 # produces much friendlier error messages. 143 year, month, day = map(int, date_string.split('-'))92 year, month, day = map(int, value.split('-')) 144 93 # This check is needed because strftime is used when saving the date 145 94 # value to the database, and strftime requires that the year be >=1900. 146 95 if year < 1900: … … def _isValidDate(date_string): 149 98 date(year, month, day) 150 99 except ValueError, e: 151 100 msg = _('Invalid date: %s') % _(str(e)) 152 raise ValidationError, msg153 101 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) 102 def validate_ansi_date(value, message_dict={}): 103 validate_ansi_date_format(value, message_dict) 104 validate_correct_ansi_date(value, message_dict) 158 105 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.')106 def validate_ansi_datetime(value, message_dict={}): 107 validate_ansi_datetime_format(value, message_dict) 108 validate_correct_ansi_date(value.split()[0], message_dict) 162 109 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]) 110 def validate_not_empty(value, message_dict={}): 111 if value.strip() == '': 112 raise ValidationError, _("Empty values are not allowed here.") 167 113 168 def isValidEmail(field_data, all_data):169 if not email_re.search(field_data):170 raise ValidationError, _( 'Enter a valid e-mail address.')114 def validate_digits_only(value, message_dict={}): 115 if not value.isdigit(): 116 raise ValidationError, _("Non-numeric characters aren't allowed here.") 171 117 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.read() 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 118 def validate_not_digits_only(value, message_dict={}): 119 if value.isdigit(): 120 raise ValidationError, _("This value can't be comprised solely of digits.") 201 121 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_data122 def validate_letters_only(value, message_dict={}): 123 if not value.isalpha(): 124 raise ValidationError, _("Only alphabetical characters are allowed here.") 205 125 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 126 def validate_lower(value, message_dict={}): 127 if value.lower() != value: 128 raise ValidationError, _("Uppercase letters are not allowed here.") 213 129 214 def isValidURL(field_data, all_data):215 if not url_re.search(field_data):216 raise ValidationError, _(" A valid URL is required.")130 def validate_upper(value, message_dict={}): 131 if value.upper() != value: 132 raise ValidationError, _("Lowercase letters are not allowed here.") 217 133 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) 134 def validate_comma_separated_integer_list(value, message_dict={}): 135 for supposed_integer in value.split(','): 136 try: 137 validate_integer(supposed_integer.strip()) 138 except ValidationError: 139 raise ValidationError, _("Enter valid integers separated by commas.") 238 140 239 def isWellFormedXmlFragment(field_data, all_data): 240 isWellFormedXml('<root>%s</root>' % field_data, all_data) 141 def validate_comma_separated_email_list(value, message_dict={}): 142 """ 143 Checks that value is a string of e-mail addresses separated by commas. 144 Blank value values will not throw a validation error, and whitespace 145 is allowed around the commas. 146 """ 147 for supposed_email in value.split(','): 148 try: 149 validate_email(supposed_email.strip()) 150 except ValidationError: 151 raise ValidationError, _("Enter valid e-mail addresses separated by commas.") 241 152 242 def isExistingURL(field_data, all_data):153 def validate_existing_url(value, message_dict={}): 243 154 try: 244 155 headers = { 245 156 "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 159 "Connection" : "close", 249 160 "User-Agent": settings.URL_VALIDATOR_USER_AGENT 250 161 } 251 req = urllib2.Request( field_data,None, headers)162 req = urllib2.Request(value,None, headers) 252 163 u = urllib2.urlopen(req) 253 164 except ValueError: 254 raise ValidationError, _("Invalid URL: %s") % field_data165 raise ValidationError, message_dict.get('invalid', _("Invalid URL: %s") % value) 255 166 except urllib2.HTTPError, e: 256 167 # 401s are valid; they just mean authorization is required. 257 168 # 301 and 302 are redirects; they just mean look somewhere else. 258 169 if str(e.code) not in ('401','301','302'): 259 raise ValidationError, _("The URL %s is a broken link.") % field_data170 raise ValidationError, message_dict.get('invalid_link', _("This URL appears to be a broken link.")) 260 171 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.read() 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) 172 raise ValidationError, message_dict.get('invalid_link', _("This URL appears to be a broken link.")) 516 173 517 174 class URLMimeTypeCheck(object): 518 175 "Checks that the provided URL points to a document with a listed mime type" … … class URLMimeTypeCheck(object): 524 181 def __init__(self, mime_type_list): 525 182 self.mime_type_list = mime_type_list 526 183 527 def __call__(self, field_data, all_data): 528 import urllib2 529 try: 530 isValidURL(field_data, all_data) 531 except ValidationError: 532 raise 184 def __call__(self, value, message_dict={}): 185 validate_existing_url(value) 533 186 try: 534 info = urllib2.urlopen( field_data).info()187 info = urllib2.urlopen(value).info() 535 188 except (urllib2.HTTPError, urllib2.URLError): 536 raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data189 raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % value 537 190 content_type = info['content-type'] 538 191 if content_type not in self.mime_type_list: 539 192 raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % { 540 'url': field_data, 'contenttype': content_type} 541 542 class RelaxNGCompact(object): 543 "Validate against a Relax NG compact schema" 544 def __init__(self, schema_path, additional_root_element=None): 545 self.schema_path = schema_path 546 self.additional_root_element = additional_root_element 547 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 193 'url': value, 'contenttype': content_type} 194 195 def validate_image_url(value, message_dict={}): 196 uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png')) 197 try: 198 uc(value, message_dict) 199 except URLMimeTypeCheck.InvalidContentType: 200 raise ValidationError, _("The URL %s does not point to a valid image.") % value 201 202 203 def validate_float(value, message_dict={}): 204 data = smart_str(value) 205 try: 206 float(data) 207 except ValueError: 208 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 338b061..e6ae4bb 100644
a b except NameError: 11 11 import django.db.models.manipulators # Imported to register signal handler. 12 12 import django.db.models.manager # Ditto. 13 13 from django.core import validators 14 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError 14 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError, ValidationError, NON_FIELD_ERRORS 15 15 from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist 16 16 from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField 17 17 from django.db.models.query import delete_objects, Q, CollectedObjects … … from django.db.models.loading import register_models, get_model 22 22 from django.dispatch import dispatcher 23 23 from django.utils.datastructures import SortedDict 24 24 from django.utils.functional import curry 25 from django.utils.translation import ugettext_lazy as _ 25 26 from django.utils.encoding import smart_str, force_unicode, smart_unicode 26 27 from django.core.files.move import file_move_safe 27 28 from django.core.files import locks … … class Model(object): 352 353 353 354 save_base.alters_data = True 354 355 355 def validate(self): 356 def clean(self, new_data=None): 357 self.to_python() 358 self.validate(new_data) 359 360 def to_python(self): 361 error_dict = {} 362 for f in self._meta.fields: 363 try: 364 value = f.to_python(getattr(self, f.attname, f.get_default())) 365 setattr(self, f.attname, value) 366 except ValidationError, e: 367 error_dict[f.name] = e.messages 368 if error_dict: 369 raise ValidationError(error_dict) 370 371 def validate(self, new_data=None): 356 372 """ 357 First coerces all fields on this instance to their proper Python types. 358 Then runs validation on every field. Returns a dictionary of 359 field_name -> error_list. 373 Validate the data on the model, if new_data is supplied, try and use those instead of 374 actual values on the fields. Note that the fields are validated separately. 360 375 """ 376 if new_data is not None: 377 def get_value(f): 378 if f.name in new_data: 379 return f.to_python(new_data[f.name]) 380 return getattr(self, f.attname, f.get_default()) 381 else: 382 get_value = lambda f: getattr(self, f.attname, f.get_default()) 361 383 error_dict = {} 362 invalid_python = {}363 384 for f in self._meta.fields: 364 385 try: 365 setattr(self, f.attname, f.to_python(getattr(self, f.attname, f.get_default()))) 366 except validators.ValidationError, e: 386 value = get_value(f) 387 f.validate(value, instance=self) 388 if hasattr(self, 'validate_%s' % f.name): 389 getattr(self, 'validate_%s' % f.name)(value) 390 except ValidationError, e: 367 391 error_dict[f.name] = e.messages 368 invalid_python[f.name] = 1 369 for f in self._meta.fields: 370 if f.name in invalid_python: 371 continue 372 errors = f.validate_full(getattr(self, f.attname, f.get_default()), self.__dict__) 373 if errors: 374 error_dict[f.name] = errors 375 return error_dict 392 393 for un_together in self._meta.unique_together: 394 lookup = {} 395 for name in un_together: 396 if name in error_dict: 397 break 398 f = self._meta.get_field(name) 399 lookup['%s__exact' % name] = get_value(f) 400 try: 401 qset = self.__class__._default_manager.all() 402 if self.pk: 403 qset = qset.exclude(pk=self.pk) 404 obj = qset.get(**lookup) 405 error_dict[NON_FIELD_ERRORS] = _('Fields %s must be unique.') % ', '.join(un_together) 406 except self.DoesNotExist: 407 pass 408 409 if error_dict: 410 raise ValidationError(error_dict) 376 411 377 412 def _collect_sub_objects(self, seen_objs, parent=None, nullable=False): 378 413 """ -
django/db/models/fields/__init__.py
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index a69cc5a..bef615b 100644
a b from django.db.models import signals 12 12 from django.db.models.query_utils import QueryWrapper 13 13 from django.dispatch import dispatcher 14 14 from django.conf import settings 15 from django.oldforms import validators as oldvalidators 15 16 from django.core import validators 16 17 from django import oldforms 17 18 from django import newforms as forms … … class Field(object): 81 82 creation_counter = 0 82 83 auto_creation_counter = -1 83 84 85 validators = [] 86 84 87 def __init__(self, verbose_name=None, name=None, primary_key=False, 85 88 max_length=None, unique=False, blank=False, null=False, 86 89 db_index=False, core=False, rel=None, default=NOT_PROVIDED, 87 90 editable=True, serialize=True, prepopulate_from=None, 88 91 unique_for_date=None, unique_for_month=None, unique_for_year=None, 89 92 validator_list=None, choices=None, radio_admin=None, help_text='', 90 db_column=None, db_tablespace=None, auto_created=False ):93 db_column=None, db_tablespace=None, auto_created=False, validators=[]): 91 94 self.name = name 92 95 self.verbose_name = verbose_name 93 96 self.primary_key = primary_key … … class Field(object): 100 103 self.core, self.rel, self.default = core, rel, default 101 104 self.editable = editable 102 105 self.serialize = serialize 106 self.validators = validators + self.validators 103 107 self.validator_list = validator_list or [] 104 108 self.prepopulate_from = prepopulate_from 105 109 self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month … … class Field(object): 167 171 return get_creation_module().DATA_TYPES[self.get_internal_type()] % data 168 172 except KeyError: 169 173 return None 170 171 174 def unique(self): 172 175 return self._unique or self.primary_key 173 176 unique = property(unique) 174 177 175 def validate _full(self, field_data, all_data):178 def validate(self, value, instance=None): 176 179 """ 177 Returns a list of errors for this field. This is the main interface, 178 as it encapsulates some basic validation logic used by all fields. 179 Subclasses should implement validate(), not validate_full(). 180 """ 181 if not self.blank and not field_data: 182 return [_('This field is required.')] 183 try: 184 self.validate(field_data, all_data) 185 except validators.ValidationError, e: 186 return e.messages 187 return [] 188 189 def validate(self, field_data, all_data): 190 """ 191 Raises validators.ValidationError if field_data has any errors. 180 Raises validators.ValidationError if value has any errors. 192 181 Subclasses should override this to specify field-specific validation 193 logic. This method should assume field_datahas already been converted182 logic. This method should assume value has already been converted 194 183 into the appropriate data type by Field.to_python(). 195 184 """ 196 pass 185 if not self.blank and self.editable and not value: 186 raise validators.ValidationError(_('This field is required.')) 187 elist = [] 188 for validator in self.validators: 189 validator(value) 190 if self.unique and instance: 191 try: 192 qset = instance.__class__._default_manager.all() 193 if instance.pk: 194 qset = qset.exclude(pk=instance.pk) 195 obj = qset.get(**{'%s__exact' % self.name : value}) 196 raise validators.ValidationError(_('This field must be unique')) 197 except instance.DoesNotExist: 198 pass 197 199 198 200 def set_attributes_from_name(self, name): 199 201 self.name = name … … class Field(object): 351 353 core_field_names.extend(f.get_manipulator_field_names(name_prefix)) 352 354 # Now, if there are any, add the validator to this FormField. 353 355 if core_field_names: 354 params['validator_list'].append( validators.RequiredIfOtherFieldsGiven(core_field_names, ugettext_lazy("This field is required.")))356 params['validator_list'].append(oldvalidators.RequiredIfOtherFieldsGiven(core_field_names, ugettext_lazy("This field is required."))) 355 357 356 358 # Finally, add the field_names. 357 359 field_names = self.get_manipulator_field_names(name_prefix) … … class DateField(Field): 547 549 return value.date() 548 550 if isinstance(value, datetime.date): 549 551 return value 550 validators.isValidANSIDate(value, None)551 552 try: 552 553 return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3]) 553 554 except ValueError: … … class DecimalField(Field): 739 740 return super(DecimalField, self).formfield(**defaults) 740 741 741 742 class EmailField(CharField): 743 validators = [validators.validate_email] 742 744 def __init__(self, *args, **kwargs): 743 745 kwargs['max_length'] = kwargs.get('max_length', 75) 744 746 CharField.__init__(self, *args, **kwargs) … … class EmailField(CharField): 746 748 def get_manipulator_field_objs(self): 747 749 return [oldforms.EmailField] 748 750 749 def validate(self, field_data, all_data):750 validators.isValidEmail(field_data, all_data)751 752 751 def formfield(self, **kwargs): 753 752 defaults = {'form_class': forms.EmailField} 754 753 defaults.update(kwargs) … … class FileField(Field): 785 784 self.always_test = True 786 785 def __call__(self, field_data, all_data): 787 786 if not all_data.get(self.other_file_field_name, False): 788 c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))787 c = oldvalidators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required.")) 789 788 c(field_data, all_data) 790 789 # First, get the core fields, if any. 791 790 core_field_names = [] … … class FileField(Field): 796 795 if core_field_names: 797 796 field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name)) 798 797 else: 799 v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))798 v = oldvalidators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required.")) 800 799 v.always_test = True 801 800 field_list[0].validator_list.append(v) 802 801 field_list[0].is_required = field_list[1].is_required = False … … class IntegerField(Field): 964 963 965 964 class IPAddressField(Field): 966 965 empty_strings_allowed = False 966 validators = [validators.validate_ip_address4] 967 967 968 def __init__(self, *args, **kwargs): 968 969 kwargs['max_length'] = 15 969 970 Field.__init__(self, *args, **kwargs) … … class IPAddressField(Field): 974 975 def get_internal_type(self): 975 976 return "IPAddressField" 976 977 977 def validate(self, field_data, all_data):978 validators.isValidIPAddress4(field_data, None)979 980 978 def formfield(self, **kwargs): 981 979 defaults = {'form_class': forms.IPAddressField} 982 980 defaults.update(kwargs) … … class NullBooleanField(Field): 1007 1005 return super(NullBooleanField, self).formfield(**defaults) 1008 1006 1009 1007 class PhoneNumberField(IntegerField): 1008 validators = [validators.validate_phone_number] 1009 1010 1010 def get_manipulator_field_objs(self): 1011 1011 return [oldforms.PhoneNumberField] 1012 1012 1013 1013 def get_internal_type(self): 1014 1014 return "PhoneNumberField" 1015 1015 1016 def validate(self, field_data, all_data):1017 validators.isValidPhone(field_data, all_data)1018 1019 1016 def formfield(self, **kwargs): 1020 1017 from django.contrib.localflavor.us.forms import USPhoneNumberField 1021 1018 defaults = {'form_class': USPhoneNumberField} … … class PositiveSmallIntegerField(IntegerField): 1047 1044 return super(PositiveSmallIntegerField, self).formfield(**defaults) 1048 1045 1049 1046 class SlugField(CharField): 1047 validators = [validators.validate_slug] 1050 1048 def __init__(self, *args, **kwargs): 1051 1049 kwargs['max_length'] = kwargs.get('max_length', 50) 1052 kwargs.setdefault('validator_list', []).append(validators.isSlug)1053 1050 # Set db_index=True unless it's been set manually. 1054 1051 if 'db_index' not in kwargs: 1055 1052 kwargs['db_index'] = True … … class URLField(CharField): 1145 1142 def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): 1146 1143 kwargs['max_length'] = kwargs.get('max_length', 200) 1147 1144 if verify_exists: 1148 kwargs.setdefault('validator _list', []).append(validators.isExistingURL)1145 kwargs.setdefault('validators', []).append(validators.validate_existing_url) 1149 1146 self.verify_exists = verify_exists 1150 1147 CharField.__init__(self, verbose_name, name, **kwargs) 1151 1148 -
django/db/models/fields/related.py
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index a1977c0..cc79030 100644
a b class ManyToManyField(RelatedField, Field): 802 802 objects = mod._default_manager.in_bulk(pks) 803 803 if len(objects) != len(pks): 804 804 badkeys = [k for k in pks if k not in objects] 805 raise validator s.ValidationError, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.",805 raise validator_list.ValidationError, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.", 806 806 "Please enter valid %(self)s IDs. The values %(value)r are invalid.", len(badkeys)) % { 807 807 'self': self.verbose_name, 808 808 '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..5d5884e 100644
a b TODO: 10 10 "This form field requires foo.js" and form.js_includes() 11 11 """ 12 12 13 from util import ValidationError13 from django.core.exceptions import ValidationError, NON_FIELD_ERRORS 14 14 from widgets import * 15 15 from fields import * 16 16 from forms import * 17 17 from models import * 18 -
django/newforms/fields.py
diff --git a/django/newforms/fields.py b/django/newforms/fields.py index ad46d78..0b728cb 100644
a b except NameError: 24 24 25 25 from django.utils.translation import ugettext_lazy as _ 26 26 from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str 27 from django.core.exceptions import ValidationError 28 from django.core import validators 27 29 28 from util import ErrorList, ValidationError29 30 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput 31 from util import ErrorList 30 32 from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile 31 33 32 34 __all__ = ( … … EMPTY_VALUES = (None, '') 46 48 47 49 class Field(object): 48 50 widget = TextInput # Default widget to use when rendering this type of Field. 51 validators = [] 49 52 hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden". 50 53 default_error_messages = { 51 54 'required': _(u'This field is required.'), … … class Field(object): 56 59 creation_counter = 0 57 60 58 61 def __init__(self, required=True, widget=None, label=None, initial=None, 59 help_text=None, error_messages=None ):62 help_text=None, error_messages=None, validators=[]): 60 63 # required -- Boolean that specifies whether the field is required. 61 64 # True by default. 62 65 # widget -- A Widget class, or instance of a Widget class, that should … … class Field(object): 70 73 # initial -- A value to use in this Field's initial display. This value 71 74 # is *not* used as a fallback if data isn't given. 72 75 # help_text -- An optional string to use as "help text" for this Field. 76 # validators -- Optional list of additional validator functions 73 77 if label is not None: 74 78 label = smart_unicode(label) 79 self.validators = self.validators + validators 75 80 self.required, self.label, self.initial = required, label, initial 76 81 self.help_text = smart_unicode(help_text or '') 77 82 widget = widget or self.widget … … class Field(object): 99 104 messages.update(error_messages or {}) 100 105 self.error_messages = messages 101 106 107 def to_python(self, value): 108 if value in EMPTY_VALUES: 109 return None 110 return smart_unicode(value) 111 112 def validate(self, value): 113 if self.required and value in EMPTY_VALUES: 114 raise ValidationError(self.error_messages['required']) 115 elif value in EMPTY_VALUES: 116 return 117 elist = ErrorList() 118 for validator in self.validators: 119 try: 120 validator(value, self.error_messages) 121 except ValidationError, e: 122 elist.extend(e.messages) 123 if elist: 124 raise ValidationError(elist) 125 102 126 def clean(self, value): 103 127 """ 104 128 Validates the given value and returns its "cleaned" value as an … … class Field(object): 106 130 107 131 Raises ValidationError for any errors. 108 132 """ 109 if self.required and value in EMPTY_VALUES:110 raise ValidationError(self.error_messages['required'])133 value = self.to_python(value) 134 self.validate(value) 111 135 return value 112 136 113 137 def widget_attrs(self, widget): … … class CharField(Field): 134 158 self.max_length, self.min_length = max_length, min_length 135 159 super(CharField, self).__init__(*args, **kwargs) 136 160 137 def clean(self, value): 138 "Validates max_length and min_length. Returns a Unicode object." 139 super(CharField, self).clean(value) 161 def to_python(self, value): 140 162 if value in EMPTY_VALUES: 141 163 return u'' 142 value = smart_unicode(value) 164 return smart_unicode(value) 165 166 def validate(self, value): 167 "Validates max_length and min_length. Returns a Unicode object." 168 super(CharField, self).validate(value) 143 169 value_length = len(value) 170 if value_length == 0 and not self.required: 171 return 144 172 if self.max_length is not None and value_length > self.max_length: 145 173 raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length}) 146 174 if self.min_length is not None and value_length < self.min_length: 147 175 raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length}) 148 return value149 176 150 177 def widget_attrs(self, widget): 151 178 if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)): … … class IntegerField(Field): 163 190 self.max_value, self.min_value = max_value, min_value 164 191 super(IntegerField, self).__init__(*args, **kwargs) 165 192 166 def clean(self, value): 167 """ 168 Validates that int() can be called on the input. Returns the result 169 of int(). Returns None for empty values. 170 """ 171 super(IntegerField, self).clean(value) 193 def to_python(self, value): 172 194 if value in EMPTY_VALUES: 173 195 return None 174 196 try: 175 value = int(str(value))197 return int(smart_str(value)) 176 198 except (ValueError, TypeError): 177 199 raise ValidationError(self.error_messages['invalid']) 200 201 def validate(self, value): 202 """ 203 Validates that int() can be called on the input. Returns the result 204 of int(). Returns None for empty values. 205 """ 206 super(IntegerField, self).validate(value) 207 if value is None: return 178 208 if self.max_value is not None and value > self.max_value: 179 209 raise ValidationError(self.error_messages['max_value'] % self.max_value) 180 210 if self.min_value is not None and value < self.min_value: 181 211 raise ValidationError(self.error_messages['min_value'] % self.min_value) 182 return value183 212 184 213 class FloatField(Field): 185 214 default_error_messages = { … … class FloatField(Field): 192 221 self.max_value, self.min_value = max_value, min_value 193 222 Field.__init__(self, *args, **kwargs) 194 223 195 def clean(self, value):224 def to_python(self, value): 196 225 """ 197 226 Validates that float() can be called on the input. Returns a float. 198 227 Returns None for empty values. 199 228 """ 200 super(FloatField, self).clean(value) 201 if not self.required and value in EMPTY_VALUES: 229 if value in EMPTY_VALUES: 202 230 return None 203 231 try: 204 value =float(value)232 return float(value) 205 233 except (ValueError, TypeError): 206 234 raise ValidationError(self.error_messages['invalid']) 235 236 def validate(self, value): 237 super(FloatField, self).validate(value) 238 if value is None: return 207 239 if self.max_value is not None and value > self.max_value: 208 240 raise ValidationError(self.error_messages['max_value'] % self.max_value) 209 241 if self.min_value is not None and value < self.min_value: 210 242 raise ValidationError(self.error_messages['min_value'] % self.min_value) 211 return value212 243 213 244 class DecimalField(Field): 214 245 default_error_messages = { … … class DecimalField(Field): 225 256 self.max_digits, self.decimal_places = max_digits, decimal_places 226 257 Field.__init__(self, *args, **kwargs) 227 258 228 def clean(self, value):259 def to_python(self, value): 229 260 """ 230 261 Validates that the input is a decimal number. Returns a Decimal 231 262 instance. Returns None for empty values. Ensures that there are no more 232 263 than max_digits in the number, and no more than decimal_places digits 233 264 after the decimal point. 234 265 """ 235 super(DecimalField, self).clean(value) 236 if not self.required and value in EMPTY_VALUES: 266 if value in EMPTY_VALUES: 237 267 return None 238 268 value = smart_str(value).strip() 239 269 try: 240 value =Decimal(value)270 return Decimal(value) 241 271 except DecimalException: 242 272 raise ValidationError(self.error_messages['invalid']) 273 274 def validate(self, value): 275 super(DecimalField, self).validate(value) 276 if value is None: return 243 277 pieces = str(value).lstrip("-").split('.') 244 278 decimals = (len(pieces) == 2) and len(pieces[1]) or 0 245 279 digits = len(pieces[0]) … … class DecimalField(Field): 253 287 raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places) 254 288 if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places): 255 289 raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) 256 return value257 290 258 291 DEFAULT_DATE_INPUT_FORMATS = ( 259 292 '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' … … class DateField(Field): 272 305 super(DateField, self).__init__(*args, **kwargs) 273 306 self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS 274 307 275 def clean(self, value):308 def to_python(self, value): 276 309 """ 277 310 Validates that the input can be converted to a date. Returns a Python 278 311 datetime.date object. 279 312 """ 280 super(DateField, self).clean(value)281 313 if value in EMPTY_VALUES: 282 314 return None 283 315 if isinstance(value, datetime.datetime): … … class TimeField(Field): 305 337 super(TimeField, self).__init__(*args, **kwargs) 306 338 self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS 307 339 308 def clean(self, value):340 def to_python(self, value): 309 341 """ 310 342 Validates that the input can be converted to a time. Returns a Python 311 343 datetime.time object. 312 344 """ 313 super(TimeField, self).clean(value)314 345 if value in EMPTY_VALUES: 315 346 return None 316 347 if isinstance(value, datetime.time): … … class DateTimeField(Field): 344 375 super(DateTimeField, self).__init__(*args, **kwargs) 345 376 self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS 346 377 347 def clean(self, value):378 def to_python(self, value): 348 379 """ 349 380 Validates that the input can be converted to a datetime. Returns a 350 381 Python datetime.datetime object. 351 382 """ 352 super(DateTimeField, self).clean(value)353 383 if value in EMPTY_VALUES: 354 384 return None 355 385 if isinstance(value, datetime.datetime): … … class RegexField(CharField): 386 416 regex = re.compile(regex) 387 417 self.regex = regex 388 418 389 def clean(self, value):419 def validate(self, value): 390 420 """ 391 421 Validates that the input matches the regular expression. Returns a 392 422 Unicode object. 393 423 """ 394 value = super(RegexField, self).clean(value)424 super(RegexField, self).validate(value) 395 425 if value == u'': 396 return value426 return 397 427 if not self.regex.search(value): 398 428 raise ValidationError(self.error_messages['invalid']) 399 return value400 429 401 430 email_re = re.compile( 402 431 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom 403 432 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string 404 433 r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain 405 434 406 class EmailField( RegexField):435 class EmailField(CharField): 407 436 default_error_messages = { 408 437 'invalid': _(u'Enter a valid e-mail address.'), 409 438 } 410 411 def __init__(self, max_length=None, min_length=None, *args, **kwargs): 412 RegexField.__init__(self, email_re, max_length, min_length, *args, 413 **kwargs) 439 validators = [validators.validate_email] 414 440 415 441 try: 416 442 from django.conf import settings … … class FileField(Field): 424 450 widget = FileInput 425 451 default_error_messages = { 426 452 'invalid': _(u"No file was submitted. Check the encoding type on the form."), 427 'missing': _(u"No file was submitted."),428 453 'empty': _(u"The submitted file is empty."), 429 454 } 430 455 431 def __init__(self, *args, **kwargs): 432 super(FileField, self).__init__(*args, **kwargs) 433 434 def clean(self, data, initial=None): 435 super(FileField, self).clean(initial or data) 456 def to_python(self, data, initial=None): 436 457 if not self.required and data in EMPTY_VALUES: 437 458 return None 438 459 elif not data and initial: … … class FileField(Field): 448 469 category = DeprecationWarning, 449 470 stacklevel = 2 450 471 ) 472 if not data: 473 raise ValidationError(self.error_messages['invalid']) 451 474 data = UploadedFile(data['filename'], data['content']) 452 475 453 476 try: … … class FileField(Field): 463 486 464 487 return data 465 488 489 def clean(self, value, initial=None): 490 "overriden clean to provide extra argument initial" 491 value = self.to_python(value, initial) 492 self.validate(value) 493 return value 494 466 495 class ImageField(FileField): 467 496 default_error_messages = { 468 497 'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."), 469 498 } 470 499 471 def clean(self, data, initial=None): 472 """ 473 Checks that the file-upload field data contains a valid image (GIF, JPG, 474 PNG, possibly others -- whatever the Python Imaging Library supports). 475 """ 476 f = super(ImageField, self).clean(data, initial) 477 if f is None: 478 return None 479 elif not data and initial: 480 return initial 500 def validate(self, data): 501 super(ImageField, self).validate(data) 502 if data is None: 503 return 481 504 from PIL import Image 482 483 505 # We need to get a file object for PIL. We might have a path or we might 484 506 # have to read the data into memory. 485 507 if hasattr(data, 'temporary_file_path'): … … class ImageField(FileField): 487 509 else: 488 510 if hasattr(data, 'read'): 489 511 file = StringIO(data.read()) 512 elif isinstance(data, UploadedFile): 513 file = StringIO(data.data.read()) 490 514 else: 491 file = StringIO(data['content'])515 file = data 492 516 493 517 try: 494 518 # load() is the only method that can spot a truncated JPEG, … … class ImageField(FileField): 507 531 trial_image.verify() 508 532 except Exception: # Python Imaging Library doesn't recognize it as an image 509 533 raise ValidationError(self.error_messages['invalid_image']) 510 return f511 534 512 535 url_re = re.compile( 513 536 r'^https?://' # http:// or https:// … … class URLField(RegexField): 530 553 self.verify_exists = verify_exists 531 554 self.user_agent = validator_user_agent 532 555 533 def clean(self, value):534 # If no URL scheme given, assume http://556 def to_python(self, value): 557 value = super(URLField, self).to_python(value) 535 558 if value and '://' not in value: 536 559 value = u'http://%s' % value 537 value = super(URLField, self).clean(value) 560 return value 561 562 def validate(self, value): 563 # If no URL scheme given, assume http:// 564 super(URLField, self).validate(value) 538 565 if value == u'': 539 return value566 return 540 567 if self.verify_exists: 541 import urllib2 542 headers = { 543 "Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", 544 "Accept-Language": "en-us,en;q=0.5", 545 "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7", 546 "Connection": "close", 547 "User-Agent": self.user_agent, 548 } 549 try: 550 req = urllib2.Request(value, None, headers) 551 u = urllib2.urlopen(req) 552 except ValueError: 553 raise ValidationError(self.error_messages['invalid']) 554 except: # urllib2.URLError, httplib.InvalidURL, etc. 555 raise ValidationError(self.error_messages['invalid_link']) 556 return value 568 # we cannot put this in self.validators because its conditional 569 validators.validate_existing_url(value, self.error_messages) 557 570 558 571 class BooleanField(Field): 559 572 widget = CheckboxInput 560 573 561 def clean(self, value):574 def to_python(self, value): 562 575 """Returns a Python boolean object.""" 563 576 # Explicitly check for the string 'False', which is what a hidden field 564 577 # will submit for False. Because bool("True") == True, we don't need to … … class BooleanField(Field): 567 580 value = False 568 581 else: 569 582 value = bool(value) 570 super(BooleanField, self).clean(value)571 if not value and self.required:572 raise ValidationError(self.error_messages['required'])573 583 return value 574 584 585 def validate(self, value): 586 if self.required and not value: 587 raise ValidationError(self.error_messages['required']) 588 589 575 590 class NullBooleanField(BooleanField): 576 591 """ 577 592 A field whose valid values are None, True and False. Invalid values are 578 593 cleaned to None. 594 595 Note that validation doesn't apply here. 579 596 """ 580 597 widget = NullBooleanSelect 581 598 582 def clean(self, value):599 def to_python(self, value): 583 600 return {True: True, False: False}.get(value, None) 584 601 602 def validate(self, value): 603 pass 604 605 585 606 class ChoiceField(Field): 586 607 widget = Select 587 608 default_error_messages = { … … class ChoiceField(Field): 605 626 606 627 choices = property(_get_choices, _set_choices) 607 628 608 def clean(self, value): 609 """ 610 Validates that the input is in self.choices. 611 """ 612 value = super(ChoiceField, self).clean(value) 613 if value in EMPTY_VALUES: 614 value = u'' 615 value = smart_unicode(value) 616 if value == u'': 617 return value 629 def validate(self, value): 630 super(ChoiceField, self).validate(value) 631 if value is None and not self.required: 632 return u'' 618 633 valid_values = set([smart_unicode(k) for k, v in self.choices]) 619 634 if value not in valid_values: 620 635 raise ValidationError(self.error_messages['invalid_choice'] % {'value': value}) 621 return value622 636 623 637 class MultipleChoiceField(ChoiceField): 624 638 hidden_widget = MultipleHiddenInput … … class MultipleChoiceField(ChoiceField): 628 642 'invalid_list': _(u'Enter a list of values.'), 629 643 } 630 644 631 def clean(self, value):645 def to_python(self, value): 632 646 """ 633 647 Validates that the input is a list or tuple. 634 648 """ 635 if self.required and not value: 636 raise ValidationError(self.error_messages['required']) 637 elif not self.required and not value: 649 if not value: 638 650 return [] 639 651 if not isinstance(value, (list, tuple)): 640 652 raise ValidationError(self.error_messages['invalid_list']) 641 new_value = [smart_unicode(val) for val in value] 653 return [smart_unicode(val) for val in value] 654 655 def validate(self, value): 642 656 # Validate that each value in the value list is in self.choices. 657 if self.required and value == []: 658 raise ValidationError(self.error_messages['required']) 643 659 valid_values = set([smart_unicode(k) for k, v in self.choices]) 644 for val in new_value:660 for val in value: 645 661 if val not in valid_values: 646 662 raise ValidationError(self.error_messages['invalid_choice'] % {'value': val}) 647 return new_value648 663 649 664 class ComboField(Field): 650 665 """ … … class ComboField(Field): 659 674 f.required = False 660 675 self.fields = fields 661 676 662 def clean(self, value): 677 def to_python(self, value): 678 for field in self.fields: 679 value = field.to_python(value) 680 return value 681 682 def validate(self, value): 663 683 """ 664 684 Validates the given value against all of self.fields, which is a 665 685 list of Field instances. 666 686 """ 667 super(ComboField, self). clean(value)687 super(ComboField, self).validate(value) 668 688 for field in self.fields: 669 value = field.clean(value) 670 return value 689 field.validate(value) 671 690 672 691 class MultiValueField(Field): 673 692 """ … … class MultiValueField(Field): 699 718 f.required = False 700 719 self.fields = fields 701 720 702 def clean(self, value):721 def to_python(self, value): 703 722 """ 704 723 Validates every value in the given list. A value is validated against 705 724 the corresponding Field in self.fields. … … class MultiValueField(Field): 713 732 if not value or isinstance(value, (list, tuple)): 714 733 if not value or not [v for v in value if v not in EMPTY_VALUES]: 715 734 if self.required: 716 r aise ValidationError(self.error_messages['required'])735 return None 717 736 else: 718 737 return self.compress([]) 719 738 else: 720 739 raise ValidationError(self.error_messages['invalid']) 740 721 741 for i, field in enumerate(self.fields): 722 742 try: 723 743 field_value = value[i] … … class SplitDateTimeField(MultiValueField): 801 821 return datetime.datetime.combine(*data_list) 802 822 return None 803 823 804 ipv4_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}$') 805 806 class IPAddressField(RegexField): 824 class IPAddressField(CharField): 807 825 default_error_messages = { 808 826 'invalid': _(u'Enter a valid IPv4 address.'), 809 827 } 810 811 def __init__(self, *args, **kwargs): 812 super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs) 828 validators = [validators.validate_ip_address4] -
django/newforms/forms.py
diff --git a/django/newforms/forms.py b/django/newforms/forms.py index fc203f3..524a903 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.newforms import ValidationError, 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, ErrorList 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): 206 206 else: 207 207 value = field.clean(value) 208 208 self.cleaned_data[name] = value 209 # FIXME deprecated - keeping this here for backwards compatibility 209 210 if hasattr(self, 'clean_%s' % name): 210 211 value = getattr(self, 'clean_%s' % name)() 211 212 self.cleaned_data[name] = value 213 214 if hasattr(self, 'validate_%s' % name): 215 getattr(self, 'validate_%s' % name)(value) 212 216 except ValidationError, e: 213 self._errors[name] = e.messages217 self._errors[name] = ErrorList(e.messages) 214 218 if name in self.cleaned_data: 215 219 del self.cleaned_data[name] 216 220 try: 217 self. cleaned_data = self.clean()221 self.validate() 218 222 except ValidationError, e: 219 self._errors[NON_FIELD_ERRORS] = e.messages 223 if hasattr(e, 'message_dict'): 224 for k, v in e.message_dict.items(): 225 self._errors.setdefault(k, []).extend(v) 226 else: 227 self._errors[NON_FIELD_ERRORS] = ErrorList(e.messages) 220 228 if self._errors: 221 229 delattr(self, 'cleaned_data') 222 230 223 231 def clean(self): 224 232 """ 233 FIXME: deprecated, use validate() instead 234 225 235 Hook for doing any extra form-wide cleaning after Field.clean() been 226 236 called on every field. Any ValidationError raised by this method will 227 237 not be associated with a particular field; it will have a special-case … … class BaseForm(StrAndUnicode): 229 239 """ 230 240 return self.cleaned_data 231 241 242 def validate(self): 243 self.cleaned_data = self.clean() 244 232 245 def is_multipart(self): 233 246 """ 234 247 Returns True if the form needs to be multipart-encrypted, i.e. it has -
django/newforms/models.py
diff --git a/django/newforms/models.py b/django/newforms/models.py index c3938d9..8511881 100644
a b from warnings import warn 8 8 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 from django.core.exceptions import ImproperlyConfigured 11 from django.core.exceptions import ImproperlyConfigured, ValidationError 12 from django.newforms.util import ErrorList 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): 258 258 object_data.update(initial) 259 259 BaseForm.__init__(self, data, files, auto_id, prefix, object_data, error_class, label_suffix) 260 260 261 def validate(self): 262 super(BaseModelForm, self).validate() 263 if self._errors: 264 return 265 self.instance.clean(self.cleaned_data) 266 261 267 def save(self, commit=True): 262 268 """ 263 269 Saves this ``form``'s cleaned_data into model instance … … class ModelChoiceField(ChoiceField): 356 362 357 363 choices = property(_get_choices, ChoiceField._set_choices) 358 364 359 def clean(self, value): 360 Field.clean(self, value) 361 if value in EMPTY_VALUES: 365 def to_python(self, value): 366 if self.required and value in EMPTY_VALUES: 367 raise ValidationError(self.error_messages['required']) 368 elif value in EMPTY_VALUES: 362 369 return None 363 370 try: 364 371 value = self.queryset.get(pk=value) … … class ModelChoiceField(ChoiceField): 366 373 raise ValidationError(self.error_messages['invalid_choice']) 367 374 return value 368 375 376 def validate(self, value): 377 pass 378 369 379 class ModelMultipleChoiceField(ModelChoiceField): 370 380 """A MultipleChoiceField whose choices are a model QuerySet.""" 371 381 hidden_widget = MultipleHiddenInput … … class ModelMultipleChoiceField(ModelChoiceField): 382 392 cache_choices, required, widget, label, initial, help_text, 383 393 *args, **kwargs) 384 394 385 def clean(self, value):395 def to_python(self, value): 386 396 if self.required and not value: 387 397 raise ValidationError(self.error_messages['required']) 388 398 elif not self.required and not value: … … class ModelMultipleChoiceField(ModelChoiceField): 398 408 else: 399 409 final_values.append(obj) 400 410 return final_values 411 -
django/newforms/util.py
diff --git a/django/newforms/util.py b/django/newforms/util.py index b3edf41..19adcc7 100644
a b class ErrorList(list, StrAndUnicode): 37 37 def __unicode__(self): 38 38 return self.as_ul() 39 39 40 def __repr__(self): 41 return repr([force_unicode(e) for e in self]) 42 40 43 def as_ul(self): 41 44 if not self: return u'' 42 45 return mark_safe(u'<ul class="errorlist">%s</ul>' … … class ErrorList(list, StrAndUnicode): 45 48 def as_text(self): 46 49 if not self: return u'' 47 50 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 2a300df..2fd510e 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..16c4ed6
- + 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.exceptions 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 # DONE 59 if not alnum_re.search(field_data): 60 raise ValidationError, _("This value must contain only letters, numbers and underscores.") 61 62 def isAlphaNumericURL(field_data, all_data): 63 # DONE 64 if not alnumurl_re.search(field_data): 65 raise ValidationError, _("This value must contain only letters, numbers, underscores, dashes or slashes.") 66 67 def isSlug(field_data, all_data): 68 # DONE 69 if not slug_re.search(field_data): 70 raise ValidationError, _("This value must contain only letters, numbers, underscores or hyphens.") 71 72 def isLowerCase(field_data, all_data): 73 # DONE 74 if field_data.lower() != field_data: 75 raise ValidationError, _("Uppercase letters are not allowed here.") 76 77 def isUpperCase(field_data, all_data): 78 # DONE 79 if field_data.upper() != field_data: 80 raise ValidationError, _("Lowercase letters are not allowed here.") 81 82 def isCommaSeparatedIntegerList(field_data, all_data): 83 # DONE 84 for supposed_int in field_data.split(','): 85 try: 86 int(supposed_int) 87 except ValueError: 88 raise ValidationError, _("Enter only digits separated by commas.") 89 90 def isCommaSeparatedEmailList(field_data, all_data): 91 # DONE 92 """ 93 Checks that field_data is a string of e-mail addresses separated by commas. 94 Blank field_data values will not throw a validation error, and whitespace 95 is allowed around the commas. 96 """ 97 for supposed_email in field_data.split(','): 98 try: 99 isValidEmail(supposed_email.strip(), '') 100 except ValidationError: 101 raise ValidationError, _("Enter valid e-mail addresses separated by commas.") 102 103 def isValidIPAddress4(field_data, all_data): 104 # DONE 105 if not ip4_re.search(field_data): 106 raise ValidationError, _("Please enter a valid IP address.") 107 108 def isNotEmpty(field_data, all_data): 109 # DONE 110 if field_data.strip() == '': 111 raise ValidationError, _("Empty values are not allowed here.") 112 113 def isOnlyDigits(field_data, all_data): 114 # DONE 115 if not field_data.isdigit(): 116 raise ValidationError, _("Non-numeric characters aren't allowed here.") 117 118 def isNotOnlyDigits(field_data, all_data): 119 # DONE 120 if field_data.isdigit(): 121 raise ValidationError, _("This value can't be comprised solely of digits.") 122 123 def isInteger(field_data, all_data): 124 # DONE 125 # This differs from isOnlyDigits because this accepts the negative sign 126 if not integer_re.search(field_data): 127 raise ValidationError, _("Enter a whole number.") 128 129 def isOnlyLetters(field_data, all_data): 130 # DONE 131 if not field_data.isalpha(): 132 raise ValidationError, _("Only alphabetical characters are allowed here.") 133 134 def _isValidDate(date_string): 135 # DONE 136 """ 137 A helper function used by isValidANSIDate and isValidANSIDatetime to 138 check if the date is valid. The date string is assumed to already be in 139 YYYY-MM-DD format. 140 """ 141 from datetime import date 142 # Could use time.strptime here and catch errors, but datetime.date below 143 # produces much friendlier error messages. 144 year, month, day = map(int, date_string.split('-')) 145 # This check is needed because strftime is used when saving the date 146 # value to the database, and strftime requires that the year be >=1900. 147 if year < 1900: 148 raise ValidationError, _('Year must be 1900 or later.') 149 try: 150 date(year, month, day) 151 except ValueError, e: 152 msg = _('Invalid date: %s') % _(str(e)) 153 raise ValidationError, msg 154 155 def isValidANSIDate(field_data, all_data): 156 # DONE 157 if not ansi_date_re.search(field_data): 158 raise ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 159 _isValidDate(field_data) 160 161 def isValidANSITime(field_data, all_data): 162 # DONE 163 if not ansi_time_re.search(field_data): 164 raise ValidationError, _('Enter a valid time in HH:MM format.') 165 166 def isValidANSIDatetime(field_data, all_data): 167 # DONE 168 if not ansi_datetime_re.search(field_data): 169 raise ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 170 _isValidDate(field_data.split()[0]) 171 172 def isValidEmail(field_data, all_data): 173 # DONE 174 if not email_re.search(field_data): 175 raise ValidationError, _('Enter a valid e-mail address.') 176 177 def isValidImage(field_data, all_data): 178 """ 179 Checks that the file-upload field data contains a valid image (GIF, JPG, 180 PNG, possibly others -- whatever the Python Imaging Library supports). 181 """ 182 from PIL import Image 183 from cStringIO import StringIO 184 try: 185 content = field_data.read() 186 except TypeError: 187 raise ValidationError, _("No file was submitted. Check the encoding type on the form.") 188 try: 189 # load() is the only method that can spot a truncated JPEG, 190 # but it cannot be called sanely after verify() 191 trial_image = Image.open(StringIO(content)) 192 trial_image.load() 193 # verify() is the only method that can spot a corrupt PNG, 194 # but it must be called immediately after the constructor 195 trial_image = Image.open(StringIO(content)) 196 trial_image.verify() 197 except Exception: # Python Imaging Library doesn't recognize it as an image 198 raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.") 199 200 def isValidImageURL(field_data, all_data): 201 uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png')) 202 try: 203 uc(field_data, all_data) 204 except URLMimeTypeCheck.InvalidContentType: 205 raise ValidationError, _("The URL %s does not point to a valid image.") % field_data 206 207 def isValidPhone(field_data, all_data): 208 if not phone_re.search(field_data): 209 raise ValidationError, _('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data 210 211 def isValidQuicktimeVideoURL(field_data, all_data): 212 "Checks that the given URL is a video that can be played by QuickTime (qt, mpeg)" 213 uc = URLMimeTypeCheck(('video/quicktime', 'video/mpeg',)) 214 try: 215 uc(field_data, all_data) 216 except URLMimeTypeCheck.InvalidContentType: 217 raise ValidationError, _("The URL %s does not point to a valid QuickTime video.") % field_data 218 219 def isValidURL(field_data, all_data): 220 if not url_re.search(field_data): 221 raise ValidationError, _("A valid URL is required.") 222 223 def isValidHTML(field_data, all_data): 224 import urllib, urllib2 225 try: 226 u = urllib2.urlopen('http://validator.w3.org/check', urllib.urlencode({'fragment': field_data, 'output': 'xml'})) 227 except: 228 # Validator or Internet connection is unavailable. Fail silently. 229 return 230 html_is_valid = (u.headers.get('x-w3c-validator-status', 'Invalid') == 'Valid') 231 if html_is_valid: 232 return 233 from xml.dom.minidom import parseString 234 error_messages = [e.firstChild.wholeText for e in parseString(u.read()).getElementsByTagName('messages')[0].getElementsByTagName('msg')] 235 raise ValidationError, _("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages) 236 237 def isWellFormedXml(field_data, all_data): 238 from xml.dom.minidom import parseString 239 try: 240 parseString(field_data) 241 except Exception, e: # Naked except because we're not sure what will be thrown 242 raise ValidationError, _("Badly formed XML: %s") % str(e) 243 244 def isWellFormedXmlFragment(field_data, all_data): 245 isWellFormedXml('<root>%s</root>' % field_data, all_data) 246 247 def isExistingURL(field_data, all_data): 248 try: 249 headers = { 250 "Accept" : "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", 251 "Accept-Language" : "en-us,en;q=0.5", 252 "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7", 253 "Connection" : "close", 254 "User-Agent": settings.URL_VALIDATOR_USER_AGENT 255 } 256 req = urllib2.Request(field_data,None, headers) 257 u = urllib2.urlopen(req) 258 except ValueError: 259 raise ValidationError, _("Invalid URL: %s") % field_data 260 except urllib2.HTTPError, e: 261 # 401s are valid; they just mean authorization is required. 262 # 301 and 302 are redirects; they just mean look somewhere else. 263 if str(e.code) not in ('401','301','302'): 264 raise ValidationError, _("The URL %s is a broken link.") % field_data 265 except: # urllib2.URLError, httplib.InvalidURL, etc. 266 raise ValidationError, _("The URL %s is a broken link.") % field_data 267 268 def isValidUSState(field_data, all_data): 269 "Checks that the given string is a valid two-letter U.S. state abbreviation" 270 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'] 271 if field_data.upper() not in states: 272 raise ValidationError, _("Enter a valid U.S. state abbreviation.") 273 274 def hasNoProfanities(field_data, all_data): 275 """ 276 Checks that the given string has no profanities in it. This does a simple 277 check for whether each profanity exists within the string, so 'fuck' will 278 catch 'motherfucker' as well. Raises a ValidationError such as: 279 Watch your mouth! The words "f--k" and "s--t" are not allowed here. 280 """ 281 field_data = field_data.lower() # normalize 282 words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data] 283 if words_seen: 284 from django.utils.text import get_text_list 285 plural = len(words_seen) 286 raise ValidationError, ungettext("Watch your mouth! The word %s is not allowed here.", 287 "Watch your mouth! The words %s are not allowed here.", plural) % \ 288 get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], _('and')) 289 290 class AlwaysMatchesOtherField(object): 291 def __init__(self, other_field_name, error_message=None): 292 self.other = other_field_name 293 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must match the '%s' field."), self.other) 294 self.always_test = True 295 296 def __call__(self, field_data, all_data): 297 if field_data != all_data[self.other]: 298 raise ValidationError, self.error_message 299 300 class ValidateIfOtherFieldEquals(object): 301 def __init__(self, other_field, other_value, validator_list): 302 self.other_field, self.other_value = other_field, other_value 303 self.validator_list = validator_list 304 self.always_test = True 305 306 def __call__(self, field_data, all_data): 307 if self.other_field in all_data and all_data[self.other_field] == self.other_value: 308 for v in self.validator_list: 309 v(field_data, all_data) 310 311 class RequiredIfOtherFieldNotGiven(object): 312 def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter something for at least one field.")): 313 self.other, self.error_message = other_field_name, error_message 314 self.always_test = True 315 316 def __call__(self, field_data, all_data): 317 if not all_data.get(self.other, False) and not field_data: 318 raise ValidationError, self.error_message 319 320 class RequiredIfOtherFieldsGiven(object): 321 def __init__(self, other_field_names, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")): 322 self.other, self.error_message = other_field_names, error_message 323 self.always_test = True 324 325 def __call__(self, field_data, all_data): 326 for field in self.other: 327 if all_data.get(field, False) and not field_data: 328 raise ValidationError, self.error_message 329 330 class RequiredIfOtherFieldGiven(RequiredIfOtherFieldsGiven): 331 "Like RequiredIfOtherFieldsGiven, but takes a single field name instead of a list." 332 def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")): 333 RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message) 334 335 class RequiredIfOtherFieldEquals(object): 336 def __init__(self, other_field, other_value, error_message=None, other_label=None): 337 self.other_field = other_field 338 self.other_value = other_value 339 other_label = other_label or other_value 340 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is %(value)s"), { 341 'field': other_field, 'value': other_label}) 342 self.always_test = True 343 344 def __call__(self, field_data, all_data): 345 if self.other_field in all_data and all_data[self.other_field] == self.other_value and not field_data: 346 raise ValidationError(self.error_message) 347 348 class RequiredIfOtherFieldDoesNotEqual(object): 349 def __init__(self, other_field, other_value, other_label=None, error_message=None): 350 self.other_field = other_field 351 self.other_value = other_value 352 other_label = other_label or other_value 353 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is not %(value)s"), { 354 'field': other_field, 'value': other_label}) 355 self.always_test = True 356 357 def __call__(self, field_data, all_data): 358 if self.other_field in all_data and all_data[self.other_field] != self.other_value and not field_data: 359 raise ValidationError(self.error_message) 360 361 class IsLessThanOtherField(object): 362 def __init__(self, other_field_name, error_message): 363 self.other, self.error_message = other_field_name, error_message 364 365 def __call__(self, field_data, all_data): 366 if field_data > all_data[self.other]: 367 raise ValidationError, self.error_message 368 369 class UniqueAmongstFieldsWithPrefix(object): 370 def __init__(self, field_name, prefix, error_message): 371 self.field_name, self.prefix = field_name, prefix 372 self.error_message = error_message or ugettext_lazy("Duplicate values are not allowed.") 373 374 def __call__(self, field_data, all_data): 375 for field_name, value in all_data.items(): 376 if field_name != self.field_name and value == field_data: 377 raise ValidationError, self.error_message 378 379 class NumberIsInRange(object): 380 """ 381 Validator that tests if a value is in a range (inclusive). 382 """ 383 def __init__(self, lower=None, upper=None, error_message=''): 384 self.lower, self.upper = lower, upper 385 if not error_message: 386 if lower and upper: 387 self.error_message = _("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper} 388 elif lower: 389 self.error_message = _("This value must be at least %s.") % lower 390 elif upper: 391 self.error_message = _("This value must be no more than %s.") % upper 392 else: 393 self.error_message = error_message 394 395 def __call__(self, field_data, all_data): 396 # Try to make the value numeric. If this fails, we assume another 397 # validator will catch the problem. 398 try: 399 val = float(field_data) 400 except ValueError: 401 return 402 403 # Now validate 404 if self.lower and self.upper and (val < self.lower or val > self.upper): 405 raise ValidationError(self.error_message) 406 elif self.lower and val < self.lower: 407 raise ValidationError(self.error_message) 408 elif self.upper and val > self.upper: 409 raise ValidationError(self.error_message) 410 411 class IsAPowerOf(object): 412 """ 413 Usage: If you create an instance of the IsPowerOf validator: 414 v = IsAPowerOf(2) 415 416 The following calls will succeed: 417 v(4, None) 418 v(8, None) 419 v(16, None) 420 421 But this call: 422 v(17, None) 423 will raise "django.core.validators.ValidationError: ['This value must be a power of 2.']" 424 """ 425 def __init__(self, power_of): 426 self.power_of = power_of 427 428 def __call__(self, field_data, all_data): 429 from math import log 430 val = log(int(field_data)) / log(self.power_of) 431 if val != int(val): 432 raise ValidationError, _("This value must be a power of %s.") % self.power_of 433 434 class IsValidDecimal(object): 435 def __init__(self, max_digits, decimal_places): 436 self.max_digits, self.decimal_places = max_digits, decimal_places 437 438 def __call__(self, field_data, all_data): 439 try: 440 val = Decimal(field_data) 441 except DecimalException: 442 raise ValidationError, _("Please enter a valid decimal number.") 443 444 pieces = str(val).lstrip("-").split('.') 445 decimals = (len(pieces) == 2) and len(pieces[1]) or 0 446 digits = len(pieces[0]) 447 448 if digits + decimals > self.max_digits: 449 raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.", 450 "Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits 451 if digits > (self.max_digits - self.decimal_places): 452 raise ValidationError, ungettext( "Please enter a valid decimal number with a whole part of at most %s digit.", 453 "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) 454 if decimals > self.decimal_places: 455 raise ValidationError, ungettext("Please enter a valid decimal number with at most %s decimal place.", 456 "Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places 457 458 def isValidFloat(field_data, all_data): 459 data = smart_str(field_data) 460 try: 461 float(data) 462 except ValueError: 463 raise ValidationError, _("Please enter a valid floating point number.") 464 465 class HasAllowableSize(object): 466 """ 467 Checks that the file-upload field data is a certain size. min_size and 468 max_size are measurements in bytes. 469 """ 470 def __init__(self, min_size=None, max_size=None, min_error_message=None, max_error_message=None): 471 self.min_size, self.max_size = min_size, max_size 472 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) 473 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) 474 475 def __call__(self, field_data, all_data): 476 try: 477 content = field_data.read() 478 except TypeError: 479 raise ValidationError, ugettext_lazy("No file was submitted. Check the encoding type on the form.") 480 if self.min_size is not None and len(content) < self.min_size: 481 raise ValidationError, self.min_error_message 482 if self.max_size is not None and len(content) > self.max_size: 483 raise ValidationError, self.max_error_message 484 485 class MatchesRegularExpression(object): 486 """ 487 Checks that the field matches the given regular-expression. The regex 488 should be in string format, not already compiled. 489 """ 490 def __init__(self, regexp, error_message=ugettext_lazy("The format for this field is wrong.")): 491 self.regexp = re.compile(regexp) 492 self.error_message = error_message 493 494 def __call__(self, field_data, all_data): 495 if not self.regexp.search(field_data): 496 raise ValidationError(self.error_message) 497 498 class AnyValidator(object): 499 """ 500 This validator tries all given validators. If any one of them succeeds, 501 validation passes. If none of them succeeds, the given message is thrown 502 as a validation error. The message is rather unspecific, so it's best to 503 specify one on instantiation. 504 """ 505 def __init__(self, validator_list=None, error_message=ugettext_lazy("This field is invalid.")): 506 if validator_list is None: validator_list = [] 507 self.validator_list = validator_list 508 self.error_message = error_message 509 for v in validator_list: 510 if hasattr(v, 'always_test'): 511 self.always_test = True 512 513 def __call__(self, field_data, all_data): 514 for v in self.validator_list: 515 try: 516 v(field_data, all_data) 517 return 518 except ValidationError, e: 519 pass 520 raise ValidationError(self.error_message) 521 522 class URLMimeTypeCheck(object): 523 "Checks that the provided URL points to a document with a listed mime type" 524 class CouldNotRetrieve(ValidationError): 525 pass 526 class InvalidContentType(ValidationError): 527 pass 528 529 def __init__(self, mime_type_list): 530 self.mime_type_list = mime_type_list 531 532 def __call__(self, field_data, all_data): 533 import urllib2 534 try: 535 isValidURL(field_data, all_data) 536 except ValidationError: 537 raise 538 try: 539 info = urllib2.urlopen(field_data).info() 540 except (urllib2.HTTPError, urllib2.URLError): 541 raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data 542 content_type = info['content-type'] 543 if content_type not in self.mime_type_list: 544 raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % { 545 'url': field_data, 'contenttype': content_type} 546 547 class RelaxNGCompact(object): 548 "Validate against a Relax NG compact schema" 549 def __init__(self, schema_path, additional_root_element=None): 550 self.schema_path = schema_path 551 self.additional_root_element = additional_root_element 552 553 def __call__(self, field_data, all_data): 554 import os, tempfile 555 if self.additional_root_element: 556 field_data = '<%(are)s>%(data)s\n</%(are)s>' % { 557 'are': self.additional_root_element, 558 'data': field_data 559 } 560 filename = tempfile.mktemp() # Insecure, but nothing else worked 561 fp = open(filename, 'w') 562 fp.write(field_data) 563 fp.close() 564 if not os.path.exists(settings.JING_PATH): 565 raise Exception, "%s not found!" % settings.JING_PATH 566 p = os.popen('%s -c %s %s' % (settings.JING_PATH, self.schema_path, filename)) 567 errors = [line.strip() for line in p.readlines()] 568 p.close() 569 os.unlink(filename) 570 display_errors = [] 571 lines = field_data.split('\n') 572 for error in errors: 573 ignored, line, level, message = error.split(':', 3) 574 # Scrape the Jing error messages to reword them more nicely. 575 m = re.search(r'Expected "(.*?)" to terminate element starting on line (\d+)', message) 576 if m: 577 display_errors.append(_('Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "%(start)s".)') % \ 578 {'tag':m.group(1).replace('/', ''), 'line':m.group(2), 'start':lines[int(m.group(2)) - 1][:30]}) 579 continue 580 if message.strip() == 'text not allowed here': 581 display_errors.append(_('Some text starting on line %(line)s is not allowed in that context. (Line starts with "%(start)s".)') % \ 582 {'line':line, 'start':lines[int(line) - 1][:30]}) 583 continue 584 m = re.search(r'\s*attribute "(.*?)" not allowed at this point; ignored', message) 585 if m: 586 display_errors.append(_('"%(attr)s" on line %(line)s is an invalid attribute. (Line starts with "%(start)s".)') % \ 587 {'attr':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 588 continue 589 m = re.search(r'\s*unknown element "(.*?)"', message) 590 if m: 591 display_errors.append(_('"<%(tag)s>" on line %(line)s is an invalid tag. (Line starts with "%(start)s".)') % \ 592 {'tag':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 593 continue 594 if message.strip() == 'required attributes missing': 595 display_errors.append(_('A tag on line %(line)s is missing one or more required attributes. (Line starts with "%(start)s".)') % \ 596 {'line':line, 'start':lines[int(line) - 1][:30]}) 597 continue 598 m = re.search(r'\s*bad value for attribute "(.*?)"', message) 599 if m: 600 display_errors.append(_('The "%(attr)s" attribute on line %(line)s has an invalid value. (Line starts with "%(start)s".)') % \ 601 {'attr':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 602 continue 603 # Failing all those checks, use the default error message. 604 display_error = 'Line %s: %s [%s]' % (line, message, level.strip()) 605 display_errors.append(display_error) 606 if len(display_errors) > 0: 607 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 f2b0e05..2b55931 100644
a b Create a new article, with categories, via the form. 485 485 ... model = Article 486 486 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01', 487 487 ... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) 488 >>> f.is_valid() 489 True 488 490 >>> new_art = f.save() 489 491 >>> new_art.id 490 492 2 … … u'...test2.txt' 859 861 >>> instance.delete() 860 862 861 863 # Test the non-required FileField 862 864 # It should fail since the field IS required on the model 863 865 >>> f = TextFileForm(data={'description': u'Assistance'}) 864 866 >>> f.fields['file'].required = False 865 867 >>> f.is_valid() 866 True 867 >>> instance = f.save() 868 >>> instance.file 869 '' 868 False 869 >>> f.errors 870 {'file': [u'This field is required.']} 870 871 871 872 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')}, instance=instance) 872 873 >>> f.is_valid() … … u'...test2.png' 968 969 >>> f = ImageFileForm(data={'description': u'Test'}) 969 970 >>> f.fields['image'].required = False 970 971 >>> f.is_valid() 971 True972 >>> instance = f.save()973 >>> instance.image 974 '' 972 False 973 >>> f.errors 974 {'image': [u'This field is required.']} 975 975 976 976 977 >>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)}, instance=instance) 977 978 >>> f.is_valid() -
tests/modeltests/validation/models.py
diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py index 63f9f7a..7d558ff 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.exceptions 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 580326f..9b62ee0 100644
a b ValidationError: [u'LENGTH 11, MAX LENGTH 10'] 204 204 205 205 >>> e = {'required': 'REQUIRED'} 206 206 >>> e['invalid'] = 'INVALID' 207 >>> e['missing'] = 'MISSING'208 207 >>> e['empty'] = 'EMPTY FILE' 209 208 >>> f = FileField(error_messages=e) 210 209 >>> f.clean('') 211 210 Traceback (most recent call last): 212 211 ... 213 ValidationError: [u' REQUIRED']212 ValidationError: [u'INVALID'] 214 213 >>> f.clean('abc') 215 214 Traceback (most recent call last): 216 215 ... 217 216 ValidationError: [u'INVALID'] 218 >>> f.clean( SimpleUploadedFile('name', None))217 >>> f.clean({}) 219 218 Traceback (most recent call last): 220 219 ... 221 ValidationError: [u' EMPTY FILE']222 >>> f.clean( SimpleUploadedFile('name', ''))220 ValidationError: [u'INVALID'] 221 >>> f.clean({'filename': 'name', 'content':''}) 223 222 Traceback (most recent call last): 224 223 ... 225 224 ValidationError: [u'EMPTY FILE'] -
tests/regressiontests/forms/fields.py
diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py index f266e7b..597a3e7 100644
a b Each Field's __init__() takes at least these parameters: 32 32 field name, if the Field is part of a Form. 33 33 initial -- A value to use in this Field's initial display. This value is 34 34 *not* used as a fallback if data isn't given. 35 validators -- Optional list of additional validator functions 35 36 36 37 Other than that, the Field subclasses have class-specific options for 37 38 __init__(). For example, CharField has a max_length option. … … u'1234567890' 104 105 >>> f.clean('1234567890a') 105 106 u'1234567890a' 106 107 108 # Custom validator functions ################################################## 109 110 >>> def validator(value, error_dict={}): raise ValidationError('validator failed') 111 >>> f = CharField(min_length=10, validators=[validator]) 112 >>> f.clean('aa') 113 Traceback (most recent call last): 114 ... 115 ValidationError: [u'validator failed'] 116 117 >>> def validator2(value, error_dict={}): raise ValidationError('validator2 failed') 118 >>> f = CharField(min_length=10, validators=[validator, validator, validator2]) 119 >>> f.clean('aa') 120 Traceback (most recent call last): 121 ... 122 ValidationError: [u'validator failed', u'validator failed', u'validator2 failed'] 123 124 >>> class MyCharField(CharField): 125 ... validators = [validator] 126 >>> f = MyCharField() 127 >>> f.clean('aa') 128 Traceback (most recent call last): 129 ... 130 ValidationError: [u'validator failed'] 131 107 132 # IntegerField ################################################################ 108 133 109 134 >>> f = IntegerField() … … ValidationError: [u'Ensure this value has at most 15 characters (it has 20).'] 748 773 >>> f.clean('') 749 774 Traceback (most recent call last): 750 775 ... 751 ValidationError: [u' This field is required.']776 ValidationError: [u'No file was submitted. Check the encoding type on the form.'] 752 777 753 778 >>> f.clean('', '') 754 779 Traceback (most recent call last): 755 780 ... 756 ValidationError: [u' This field is required.']781 ValidationError: [u'No file was submitted. Check the encoding type on the form.'] 757 782 758 783 >>> f.clean('', 'files/test1.pdf') 759 784 'files/test1.pdf' … … ValidationError: [u'This field is required.'] 761 786 >>> f.clean(None) 762 787 Traceback (most recent call last): 763 788 ... 764 ValidationError: [u' This field is required.']789 ValidationError: [u'No file was submitted. Check the encoding type on the form.'] 765 790 766 791 >>> f.clean(None, '') 767 792 Traceback (most recent call last): 768 793 ... 769 ValidationError: [u' This field is required.']794 ValidationError: [u'No file was submitted. Check the encoding type on the form.'] 770 795 771 796 >>> f.clean(None, 'files/test2.pdf') 772 797 'files/test2.pdf' … … ValidationError: [u'Select a valid choice. That choice is not one of the availab 1000 1025 1001 1026 >>> f = ChoiceField(choices=[('1', '1'), ('2', '2')], required=False) 1002 1027 >>> f.clean('') 1003 u''1004 1028 >>> f.clean(None) 1005 u''1006 1029 >>> f.clean(1) 1007 1030 u'1' 1008 1031 >>> f.clean('1') -
tests/regressiontests/forms/forms.py
diff --git a/tests/regressiontests/forms/forms.py b/tests/regressiontests/forms/forms.py index 041fa40..b70b71a 100644
a b not request.POST. 1464 1464 1465 1465 >>> f = FileForm(data={}, files={}, auto_id=False) 1466 1466 >>> print f 1467 <tr><th>File1:</th><td><ul class="errorlist"><li> This field is required.</li></ul><input type="file" name="file1" /></td></tr>1467 <tr><th>File1:</th><td><ul class="errorlist"><li>No file was submitted. Check the encoding type on the form.</li></ul><input type="file" name="file1" /></td></tr> 1468 1468 1469 1469 >>> f = FileForm(data={}, files={'file1': SimpleUploadedFile('name', '')}, auto_id=False) 1470 1470 >>> print f -
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/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 """