Ticket #6845: 6845-against-8198.patch
File 6845-against-8198.patch, 132.4 KB (added by , 16 years ago) |
---|
-
AUTHORS
commit ccf27602e0b9fa46bbe3a246a45ae7524ed574be Author: Honza Král <Honza.Kral@gmail.com> Date: Sun Aug 3 18:28:59 2008 +0200 Ticket #6845 diff --git a/AUTHORS b/AUTHORS index a9f5583..633070c 100644
a b answer newbie questions, and generally made Django that much better: 225 225 Igor Kolar <ike@email.si> 226 226 Gasper Koren 227 227 Martin Kosír <martin@martinkosir.net> 228 Honza Kral <Honza.Kral@gmail.com> 228 229 Meir Kriheli <http://mksoft.co.il/> 229 230 Bruce Kroeze <http://coderseye.com/> 230 231 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/management/commands/createsuperuser.py
diff --git a/django/contrib/auth/management/commands/createsuperuser.py b/django/contrib/auth/management/commands/createsuperuser.py index 91e39f7..f8492f8 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 3ea184a..4c381c9 100644
a b class User(models.Model): 131 131 132 132 Username and password are required. Other fields are optional. 133 133 """ 134 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)."))134 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).")) 135 135 first_name = models.CharField(_('first name'), max_length=30, blank=True) 136 136 last_name = models.CharField(_('last name'), max_length=30, blank=True) 137 137 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 ba59cba..87d60f9 100644
a b 1 1 import base64 2 2 import datetime 3 3 4 from django. coreimport validators4 from django.oldforms import validators 5 5 from django import oldforms 6 6 from django.core.mail import mail_admins, mail_managers 7 7 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 466425c..c69be18 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 6d0a038..27505b2 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 2b82a79..f9d9125 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 c86dbaf..40b1407 100644
a b 2 2 JP-specific Form helpers 3 3 """ 4 4 5 from django.core import validators6 from django.forms import ValidationError7 5 from django.utils.translation import ugettext_lazy as _ 8 6 from django.forms.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 f94db40..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('-')) 93 # This check is needed because strftime is used when saving the date 94 # value to the database, and strftime requires that the year be >=1900. 95 if year < 1900: 96 raise ValidationError, _('Year must be 1900 or later.') 144 97 try: 145 98 date(year, month, day) 146 99 except ValueError, e: 147 100 msg = _('Invalid date: %s') % _(str(e)) 148 raise ValidationError, msg149 101 150 def isValidANSIDate(field_data, all_data): 151 if not ansi_date_re.search(field_data): 152 raise ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 153 _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) 154 105 155 def isValidANSITime(field_data, all_data):156 if not ansi_time_re.search(field_data):157 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) 158 109 159 def isValidANSIDatetime(field_data, all_data): 160 if not ansi_datetime_re.search(field_data): 161 raise ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 162 _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.") 163 113 164 def isValidEmail(field_data, all_data):165 if not email_re.search(field_data):166 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.") 167 117 168 def isValidImage(field_data, all_data): 169 """ 170 Checks that the file-upload field data contains a valid image (GIF, JPG, 171 PNG, possibly others -- whatever the Python Imaging Library supports). 172 """ 173 from PIL import Image 174 from cStringIO import StringIO 175 try: 176 content = field_data.read() 177 except TypeError: 178 raise ValidationError, _("No file was submitted. Check the encoding type on the form.") 179 try: 180 # load() is the only method that can spot a truncated JPEG, 181 # but it cannot be called sanely after verify() 182 trial_image = Image.open(StringIO(content)) 183 trial_image.load() 184 # verify() is the only method that can spot a corrupt PNG, 185 # but it must be called immediately after the constructor 186 trial_image = Image.open(StringIO(content)) 187 trial_image.verify() 188 except Exception: # Python Imaging Library doesn't recognize it as an image 189 raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.") 190 191 def isValidImageURL(field_data, all_data): 192 uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png')) 193 try: 194 uc(field_data, all_data) 195 except URLMimeTypeCheck.InvalidContentType: 196 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.") 197 121 198 def isValidPhone(field_data, all_data):199 if not phone_re.search(field_data):200 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.") 201 125 202 def isValidQuicktimeVideoURL(field_data, all_data): 203 "Checks that the given URL is a video that can be played by QuickTime (qt, mpeg)" 204 uc = URLMimeTypeCheck(('video/quicktime', 'video/mpeg',)) 205 try: 206 uc(field_data, all_data) 207 except URLMimeTypeCheck.InvalidContentType: 208 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.") 209 129 210 def isValidURL(field_data, all_data):211 if not url_re.search(field_data):212 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.") 213 133 214 def isValidHTML(field_data, all_data): 215 import urllib, urllib2 216 try: 217 u = urllib2.urlopen('http://validator.w3.org/check', urllib.urlencode({'fragment': field_data, 'output': 'xml'})) 218 except: 219 # Validator or Internet connection is unavailable. Fail silently. 220 return 221 html_is_valid = (u.headers.get('x-w3c-validator-status', 'Invalid') == 'Valid') 222 if html_is_valid: 223 return 224 from xml.dom.minidom import parseString 225 error_messages = [e.firstChild.wholeText for e in parseString(u.read()).getElementsByTagName('messages')[0].getElementsByTagName('msg')] 226 raise ValidationError, _("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages) 227 228 def isWellFormedXml(field_data, all_data): 229 from xml.dom.minidom import parseString 230 try: 231 parseString(field_data) 232 except Exception, e: # Naked except because we're not sure what will be thrown 233 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.") 234 140 235 def isWellFormedXmlFragment(field_data, all_data): 236 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.") 237 152 238 def isExistingURL(field_data, all_data):153 def validate_existing_url(value, message_dict={}): 239 154 try: 240 155 headers = { 241 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): 244 159 "Connection" : "close", 245 160 "User-Agent": settings.URL_VALIDATOR_USER_AGENT 246 161 } 247 req = urllib2.Request( field_data,None, headers)162 req = urllib2.Request(value,None, headers) 248 163 u = urllib2.urlopen(req) 249 164 except ValueError: 250 raise ValidationError, _("Invalid URL: %s") % field_data165 raise ValidationError, message_dict.get('invalid', _("Invalid URL: %s") % value) 251 166 except urllib2.HTTPError, e: 252 167 # 401s are valid; they just mean authorization is required. 253 168 # 301 and 302 are redirects; they just mean look somewhere else. 254 169 if str(e.code) not in ('401','301','302'): 255 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.")) 256 171 except: # urllib2.URLError, httplib.InvalidURL, etc. 257 raise ValidationError, _("The URL %s is a broken link.") % field_data 258 259 def isValidUSState(field_data, all_data): 260 "Checks that the given string is a valid two-letter U.S. state abbreviation" 261 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'] 262 if field_data.upper() not in states: 263 raise ValidationError, _("Enter a valid U.S. state abbreviation.") 264 265 def hasNoProfanities(field_data, all_data): 266 """ 267 Checks that the given string has no profanities in it. This does a simple 268 check for whether each profanity exists within the string, so 'fuck' will 269 catch 'motherfucker' as well. Raises a ValidationError such as: 270 Watch your mouth! The words "f--k" and "s--t" are not allowed here. 271 """ 272 field_data = field_data.lower() # normalize 273 words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data] 274 if words_seen: 275 from django.utils.text import get_text_list 276 plural = len(words_seen) 277 raise ValidationError, ungettext("Watch your mouth! The word %s is not allowed here.", 278 "Watch your mouth! The words %s are not allowed here.", plural) % \ 279 get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], _('and')) 280 281 class AlwaysMatchesOtherField(object): 282 def __init__(self, other_field_name, error_message=None): 283 self.other = other_field_name 284 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must match the '%s' field."), self.other) 285 self.always_test = True 286 287 def __call__(self, field_data, all_data): 288 if field_data != all_data[self.other]: 289 raise ValidationError, self.error_message 290 291 class ValidateIfOtherFieldEquals(object): 292 def __init__(self, other_field, other_value, validator_list): 293 self.other_field, self.other_value = other_field, other_value 294 self.validator_list = validator_list 295 self.always_test = True 296 297 def __call__(self, field_data, all_data): 298 if self.other_field in all_data and all_data[self.other_field] == self.other_value: 299 for v in self.validator_list: 300 v(field_data, all_data) 301 302 class RequiredIfOtherFieldNotGiven(object): 303 def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter something for at least one field.")): 304 self.other, self.error_message = other_field_name, error_message 305 self.always_test = True 306 307 def __call__(self, field_data, all_data): 308 if not all_data.get(self.other, False) and not field_data: 309 raise ValidationError, self.error_message 310 311 class RequiredIfOtherFieldsGiven(object): 312 def __init__(self, other_field_names, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")): 313 self.other, self.error_message = other_field_names, error_message 314 self.always_test = True 315 316 def __call__(self, field_data, all_data): 317 for field in self.other: 318 if all_data.get(field, False) and not field_data: 319 raise ValidationError, self.error_message 320 321 class RequiredIfOtherFieldGiven(RequiredIfOtherFieldsGiven): 322 "Like RequiredIfOtherFieldsGiven, but takes a single field name instead of a list." 323 def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")): 324 RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message) 325 326 class RequiredIfOtherFieldEquals(object): 327 def __init__(self, other_field, other_value, error_message=None, other_label=None): 328 self.other_field = other_field 329 self.other_value = other_value 330 other_label = other_label or other_value 331 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is %(value)s"), { 332 'field': other_field, 'value': other_label}) 333 self.always_test = True 334 335 def __call__(self, field_data, all_data): 336 if self.other_field in all_data and all_data[self.other_field] == self.other_value and not field_data: 337 raise ValidationError(self.error_message) 338 339 class RequiredIfOtherFieldDoesNotEqual(object): 340 def __init__(self, other_field, other_value, other_label=None, error_message=None): 341 self.other_field = other_field 342 self.other_value = other_value 343 other_label = other_label or other_value 344 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is not %(value)s"), { 345 'field': other_field, 'value': other_label}) 346 self.always_test = True 347 348 def __call__(self, field_data, all_data): 349 if self.other_field in all_data and all_data[self.other_field] != self.other_value and not field_data: 350 raise ValidationError(self.error_message) 351 352 class IsLessThanOtherField(object): 353 def __init__(self, other_field_name, error_message): 354 self.other, self.error_message = other_field_name, error_message 355 356 def __call__(self, field_data, all_data): 357 if field_data > all_data[self.other]: 358 raise ValidationError, self.error_message 359 360 class UniqueAmongstFieldsWithPrefix(object): 361 def __init__(self, field_name, prefix, error_message): 362 self.field_name, self.prefix = field_name, prefix 363 self.error_message = error_message or ugettext_lazy("Duplicate values are not allowed.") 364 365 def __call__(self, field_data, all_data): 366 for field_name, value in all_data.items(): 367 if field_name != self.field_name and value == field_data: 368 raise ValidationError, self.error_message 369 370 class NumberIsInRange(object): 371 """ 372 Validator that tests if a value is in a range (inclusive). 373 """ 374 def __init__(self, lower=None, upper=None, error_message=''): 375 self.lower, self.upper = lower, upper 376 if not error_message: 377 if lower and upper: 378 self.error_message = _("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper} 379 elif lower: 380 self.error_message = _("This value must be at least %s.") % lower 381 elif upper: 382 self.error_message = _("This value must be no more than %s.") % upper 383 else: 384 self.error_message = error_message 385 386 def __call__(self, field_data, all_data): 387 # Try to make the value numeric. If this fails, we assume another 388 # validator will catch the problem. 389 try: 390 val = float(field_data) 391 except ValueError: 392 return 393 394 # Now validate 395 if self.lower and self.upper and (val < self.lower or val > self.upper): 396 raise ValidationError(self.error_message) 397 elif self.lower and val < self.lower: 398 raise ValidationError(self.error_message) 399 elif self.upper and val > self.upper: 400 raise ValidationError(self.error_message) 401 402 class IsAPowerOf(object): 403 """ 404 Usage: If you create an instance of the IsPowerOf validator: 405 v = IsAPowerOf(2) 406 407 The following calls will succeed: 408 v(4, None) 409 v(8, None) 410 v(16, None) 411 412 But this call: 413 v(17, None) 414 will raise "django.core.validators.ValidationError: ['This value must be a power of 2.']" 415 """ 416 def __init__(self, power_of): 417 self.power_of = power_of 418 419 def __call__(self, field_data, all_data): 420 from math import log 421 val = log(int(field_data)) / log(self.power_of) 422 if val != int(val): 423 raise ValidationError, _("This value must be a power of %s.") % self.power_of 424 425 class IsValidDecimal(object): 426 def __init__(self, max_digits, decimal_places): 427 self.max_digits, self.decimal_places = max_digits, decimal_places 428 429 def __call__(self, field_data, all_data): 430 try: 431 val = Decimal(field_data) 432 except DecimalException: 433 raise ValidationError, _("Please enter a valid decimal number.") 434 435 pieces = str(val).lstrip("-").split('.') 436 decimals = (len(pieces) == 2) and len(pieces[1]) or 0 437 digits = len(pieces[0]) 438 439 if digits + decimals > self.max_digits: 440 raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.", 441 "Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits 442 if digits > (self.max_digits - self.decimal_places): 443 raise ValidationError, ungettext( "Please enter a valid decimal number with a whole part of at most %s digit.", 444 "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) 445 if decimals > self.decimal_places: 446 raise ValidationError, ungettext("Please enter a valid decimal number with at most %s decimal place.", 447 "Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places 448 449 def isValidFloat(field_data, all_data): 450 data = smart_str(field_data) 451 try: 452 float(data) 453 except ValueError: 454 raise ValidationError, _("Please enter a valid floating point number.") 455 456 class HasAllowableSize(object): 457 """ 458 Checks that the file-upload field data is a certain size. min_size and 459 max_size are measurements in bytes. 460 """ 461 def __init__(self, min_size=None, max_size=None, min_error_message=None, max_error_message=None): 462 self.min_size, self.max_size = min_size, max_size 463 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) 464 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) 465 466 def __call__(self, field_data, all_data): 467 try: 468 content = field_data.read() 469 except TypeError: 470 raise ValidationError, ugettext_lazy("No file was submitted. Check the encoding type on the form.") 471 if self.min_size is not None and len(content) < self.min_size: 472 raise ValidationError, self.min_error_message 473 if self.max_size is not None and len(content) > self.max_size: 474 raise ValidationError, self.max_error_message 475 476 class MatchesRegularExpression(object): 477 """ 478 Checks that the field matches the given regular-expression. The regex 479 should be in string format, not already compiled. 480 """ 481 def __init__(self, regexp, error_message=ugettext_lazy("The format for this field is wrong.")): 482 self.regexp = re.compile(regexp) 483 self.error_message = error_message 484 485 def __call__(self, field_data, all_data): 486 if not self.regexp.search(field_data): 487 raise ValidationError(self.error_message) 488 489 class AnyValidator(object): 490 """ 491 This validator tries all given validators. If any one of them succeeds, 492 validation passes. If none of them succeeds, the given message is thrown 493 as a validation error. The message is rather unspecific, so it's best to 494 specify one on instantiation. 495 """ 496 def __init__(self, validator_list=None, error_message=ugettext_lazy("This field is invalid.")): 497 if validator_list is None: validator_list = [] 498 self.validator_list = validator_list 499 self.error_message = error_message 500 for v in validator_list: 501 if hasattr(v, 'always_test'): 502 self.always_test = True 503 504 def __call__(self, field_data, all_data): 505 for v in self.validator_list: 506 try: 507 v(field_data, all_data) 508 return 509 except ValidationError, e: 510 pass 511 raise ValidationError(self.error_message) 172 raise ValidationError, message_dict.get('invalid_link', _("This URL appears to be a broken link.")) 512 173 513 174 class URLMimeTypeCheck(object): 514 175 "Checks that the provided URL points to a document with a listed mime type" … … class URLMimeTypeCheck(object): 520 181 def __init__(self, mime_type_list): 521 182 self.mime_type_list = mime_type_list 522 183 523 def __call__(self, field_data, all_data): 524 import urllib2 525 try: 526 isValidURL(field_data, all_data) 527 except ValidationError: 528 raise 184 def __call__(self, value, message_dict={}): 185 validate_existing_url(value) 529 186 try: 530 info = urllib2.urlopen( field_data).info()187 info = urllib2.urlopen(value).info() 531 188 except (urllib2.HTTPError, urllib2.URLError): 532 raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data189 raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % value 533 190 content_type = info['content-type'] 534 191 if content_type not in self.mime_type_list: 535 192 raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % { 536 'url': field_data, 'contenttype': content_type} 537 538 class RelaxNGCompact(object): 539 "Validate against a Relax NG compact schema" 540 def __init__(self, schema_path, additional_root_element=None): 541 self.schema_path = schema_path 542 self.additional_root_element = additional_root_element 543 544 def __call__(self, field_data, all_data): 545 import os, tempfile 546 if self.additional_root_element: 547 field_data = '<%(are)s>%(data)s\n</%(are)s>' % { 548 'are': self.additional_root_element, 549 'data': field_data 550 } 551 filename = tempfile.mktemp() # Insecure, but nothing else worked 552 fp = open(filename, 'w') 553 fp.write(field_data) 554 fp.close() 555 if not os.path.exists(settings.JING_PATH): 556 raise Exception, "%s not found!" % settings.JING_PATH 557 p = os.popen('%s -c %s %s' % (settings.JING_PATH, self.schema_path, filename)) 558 errors = [line.strip() for line in p.readlines()] 559 p.close() 560 os.unlink(filename) 561 display_errors = [] 562 lines = field_data.split('\n') 563 for error in errors: 564 ignored, line, level, message = error.split(':', 3) 565 # Scrape the Jing error messages to reword them more nicely. 566 m = re.search(r'Expected "(.*?)" to terminate element starting on line (\d+)', message) 567 if m: 568 display_errors.append(_('Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "%(start)s".)') % \ 569 {'tag':m.group(1).replace('/', ''), 'line':m.group(2), 'start':lines[int(m.group(2)) - 1][:30]}) 570 continue 571 if message.strip() == 'text not allowed here': 572 display_errors.append(_('Some text starting on line %(line)s is not allowed in that context. (Line starts with "%(start)s".)') % \ 573 {'line':line, 'start':lines[int(line) - 1][:30]}) 574 continue 575 m = re.search(r'\s*attribute "(.*?)" not allowed at this point; ignored', message) 576 if m: 577 display_errors.append(_('"%(attr)s" on line %(line)s is an invalid attribute. (Line starts with "%(start)s".)') % \ 578 {'attr':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 579 continue 580 m = re.search(r'\s*unknown element "(.*?)"', message) 581 if m: 582 display_errors.append(_('"<%(tag)s>" on line %(line)s is an invalid tag. (Line starts with "%(start)s".)') % \ 583 {'tag':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 584 continue 585 if message.strip() == 'required attributes missing': 586 display_errors.append(_('A tag on line %(line)s is missing one or more required attributes. (Line starts with "%(start)s".)') % \ 587 {'line':line, 'start':lines[int(line) - 1][:30]}) 588 continue 589 m = re.search(r'\s*bad value for attribute "(.*?)"', message) 590 if m: 591 display_errors.append(_('The "%(attr)s" attribute on line %(line)s has an invalid value. (Line starts with "%(start)s".)') % \ 592 {'attr':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 593 continue 594 # Failing all those checks, use the default error message. 595 display_error = 'Line %s: %s [%s]' % (line, message, level.strip()) 596 display_errors.append(display_error) 597 if len(display_errors) > 0: 598 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 18c47e8..97e582c 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 7d7def3..142f3ad 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, FieldError15 14 from django.db.models.fields import AutoField, ImageField 15 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError, ValidationError, NON_FIELD_ERRORS 16 16 from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField 17 17 from django.db.models.query import delete_objects, Q, CollectedObjects 18 18 from django.db.models.options import Options … … from django.db.models import signals 21 21 from django.db.models.loading import register_models, get_model 22 22 from django.dispatch import dispatcher 23 23 from django.utils.functional import curry 24 from django.utils.translation import ugettext_lazy as _ 24 25 from django.utils.encoding import smart_str, force_unicode, smart_unicode 25 26 from django.core.files.move import file_move_safe 26 27 from django.core.files import locks … … class Model(object): 356 357 357 358 save_base.alters_data = True 358 359 359 def validate(self): 360 def clean(self, new_data=None): 361 self.to_python() 362 self.validate(new_data) 363 364 def to_python(self): 365 error_dict = {} 366 for f in self._meta.fields: 367 try: 368 value = f.to_python(getattr(self, f.attname, f.get_default())) 369 setattr(self, f.attname, value) 370 except ValidationError, e: 371 error_dict[f.name] = e.messages 372 if error_dict: 373 raise ValidationError(error_dict) 374 375 def validate(self, new_data=None): 360 376 """ 361 First coerces all fields on this instance to their proper Python types. 362 Then runs validation on every field. Returns a dictionary of 363 field_name -> error_list. 377 Validate the data on the model, if new_data is supplied, try and use those instead of 378 actual values on the fields. Note that the fields are validated separately. 364 379 """ 380 if new_data is not None: 381 def get_value(f): 382 if f.name in new_data: 383 return f.to_python(new_data[f.name]) 384 return getattr(self, f.attname, f.get_default()) 385 else: 386 get_value = lambda f: getattr(self, f.attname, f.get_default()) 365 387 error_dict = {} 366 invalid_python = {}367 388 for f in self._meta.fields: 368 389 try: 369 setattr(self, f.attname, f.to_python(getattr(self, f.attname, f.get_default()))) 370 except validators.ValidationError, e: 390 value = get_value(f) 391 f.validate(value, self) 392 if hasattr(self, 'validate_%s' % f.name): 393 getattr(self, 'validate_%s' % f.name)(value) 394 except ValidationError, e: 371 395 error_dict[f.name] = e.messages 372 invalid_python[f.name] = 1 373 for f in self._meta.fields: 374 if f.name in invalid_python: 375 continue 376 errors = f.validate_full(getattr(self, f.attname, f.get_default()), self.__dict__) 377 if errors: 378 error_dict[f.name] = errors 379 return error_dict 396 397 for un_together in self._meta.unique_together: 398 lookup = {} 399 for name in un_together: 400 if name in error_dict: 401 break 402 f = self._meta.get_field(name) 403 lookup['%s__exact' % name] = get_value(f) 404 try: 405 qset = self.__class__._default_manager.all() 406 if self.pk: 407 qset = qset.exclude(pk=self.pk) 408 obj = qset.get(**lookup) 409 error_dict[NON_FIELD_ERRORS] = _('Fields %s must be unique.') % ', '.join(un_together) 410 except self.DoesNotExist: 411 pass 412 413 if error_dict: 414 raise ValidationError(error_dict) 380 415 381 416 def _collect_sub_objects(self, seen_objs, parent=None, nullable=False): 382 417 """ -
django/db/models/fields/__init__.py
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 494c42c..1783264 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 forms … … class Field(object): 71 72 creation_counter = 0 72 73 auto_creation_counter = -1 73 74 75 validators = [] 76 74 77 def __init__(self, verbose_name=None, name=None, primary_key=False, 75 78 max_length=None, unique=False, blank=False, null=False, 76 79 db_index=False, core=False, rel=None, default=NOT_PROVIDED, 77 80 editable=True, serialize=True, unique_for_date=None, 78 81 unique_for_month=None, unique_for_year=None, validator_list=None, 79 82 choices=None, help_text='', db_column=None, db_tablespace=None, 80 auto_created=False ):83 auto_created=False, validators=[]): 81 84 self.name = name 82 85 self.verbose_name = verbose_name 83 86 self.primary_key = primary_key … … class Field(object): 90 93 self.core, self.rel, self.default = core, rel, default 91 94 self.editable = editable 92 95 self.serialize = serialize 96 self.validators = validators + self.validators 93 97 self.validator_list = validator_list or [] 94 98 self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month 95 99 self.unique_for_year = unique_for_year … … class Field(object): 155 159 return get_creation_module().DATA_TYPES[self.get_internal_type()] % data 156 160 except KeyError: 157 161 return None 158 159 162 def unique(self): 160 163 return self._unique or self.primary_key 161 164 unique = property(unique) 162 165 163 def validate_full(self, field_data, all_data): 164 """ 165 Returns a list of errors for this field. This is the main interface, 166 as it encapsulates some basic validation logic used by all fields. 167 Subclasses should implement validate(), not validate_full(). 168 """ 169 if not self.blank and not field_data: 170 return [_('This field is required.')] 171 try: 172 self.validate(field_data, all_data) 173 except validators.ValidationError, e: 174 return e.messages 175 return [] 176 177 def validate(self, field_data, all_data): 166 def validate(self, value, instance): 178 167 """ 179 Raises validators.ValidationError if field_datahas any errors.168 Raises validators.ValidationError if value has any errors. 180 169 Subclasses should override this to specify field-specific validation 181 logic. This method should assume field_datahas already been converted170 logic. This method should assume value has already been converted 182 171 into the appropriate data type by Field.to_python(). 183 172 """ 184 pass 173 if not self.blank and self.editable and not value: 174 raise validators.ValidationError(_('This field is required.')) 175 elist = [] 176 for validator in self.validators: 177 validator(value) 178 179 # ??? shouldn't we move these into model.validate_FIELD() via contribute_to_class ??? 180 # validate uniqueness unless we are the PK 181 if self.unique and (not instance._meta.pk == self): 182 try: 183 qset = instance.__class__._default_manager.all() 184 if instance.pk: 185 qset = qset.exclude(pk=instance.pk) 186 obj = qset.get(**{'%s__exact' % self.name : value}) 187 raise validators.ValidationError(_('This field must be unique')) 188 except instance.DoesNotExist: 189 pass 190 191 if self.unique_for_date: 192 try: 193 qset = instance.__class__._default_manager.all() 194 unique_for = getattr(instance, self.unique_for_date) 195 obj = qset.get(**{ 196 '%s__exact' % self.name : value, 197 '%s__year' % self.unique_for_date: unique_for.year, 198 '%s__month' % self.unique_for_date: unique_for.month, 199 '%s__day' % self.unique_for_date: unique_for.day 200 }) 201 raise validators.ValidationError(_('This field must be unique for %s') % self.unique_for_date ) 202 except instance.DoesNotExist: 203 pass 204 205 if self.unique_for_month: 206 try: 207 qset = instance.__class__._default_manager.all() 208 unique_for = getattr(instance, self.unique_for_date) 209 obj = qset.get(**{ 210 '%s__exact' % self.name : value, 211 '%s__year' % self.unique_for_date: unique_for.year, 212 '%s__month' % self.unique_for_date: unique_for.month, 213 }) 214 raise validators.ValidationError(_('This field must be unique for %s') % self.unique_for_date ) 215 except instance.DoesNotExist: 216 pass 217 pass 218 219 if self.unique_for_year: 220 try: 221 qset = instance.__class__._default_manager.all() 222 unique_for = getattr(instance, self.unique_for_date) 223 obj = qset.get(**{ 224 '%s__exact' % self.name : value, 225 '%s__year' % self.unique_for_date: unique_for.year, 226 }) 227 raise validators.ValidationError(_('This field must be unique for %s') % self.unique_for_date ) 228 except instance.DoesNotExist: 229 pass 185 230 186 231 def set_attributes_from_name(self, name): 187 232 self.name = name … … class Field(object): 340 385 core_field_names.extend(f.get_manipulator_field_names(name_prefix)) 341 386 # Now, if there are any, add the validator to this FormField. 342 387 if core_field_names: 343 params['validator_list'].append( validators.RequiredIfOtherFieldsGiven(core_field_names, ugettext_lazy("This field is required.")))388 params['validator_list'].append(oldvalidators.RequiredIfOtherFieldsGiven(core_field_names, ugettext_lazy("This field is required."))) 344 389 345 390 # Finally, add the field_names. 346 391 field_names = self.get_manipulator_field_names(name_prefix) … … class DateField(Field): 562 607 return value.date() 563 608 if isinstance(value, datetime.date): 564 609 return value 565 validators.isValidANSIDate(value, None)566 610 try: 567 611 return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3]) 568 612 except ValueError: … … class DecimalField(Field): 743 787 return super(DecimalField, self).formfield(**defaults) 744 788 745 789 class EmailField(CharField): 790 validators = [validators.validate_email] 746 791 def __init__(self, *args, **kwargs): 747 792 kwargs['max_length'] = kwargs.get('max_length', 75) 748 793 CharField.__init__(self, *args, **kwargs) … … class EmailField(CharField): 750 795 def get_manipulator_field_objs(self): 751 796 return [oldforms.EmailField] 752 797 753 def validate(self, field_data, all_data):754 validators.isValidEmail(field_data, all_data)755 756 798 def formfield(self, **kwargs): 757 799 defaults = {'form_class': forms.EmailField} 758 800 defaults.update(kwargs) … … class FileField(Field): 789 831 self.always_test = True 790 832 def __call__(self, field_data, all_data): 791 833 if not all_data.get(self.other_file_field_name, False): 792 c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))834 c = oldvalidators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required.")) 793 835 c(field_data, all_data) 794 836 # First, get the core fields, if any. 795 837 core_field_names = [] … … class FileField(Field): 800 842 if core_field_names: 801 843 field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name)) 802 844 else: 803 v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))845 v = oldvalidators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required.")) 804 846 v.always_test = True 805 847 field_list[0].validator_list.append(v) 806 848 field_list[0].is_required = field_list[1].is_required = False … … class IntegerField(Field): 978 1020 979 1021 class IPAddressField(Field): 980 1022 empty_strings_allowed = False 1023 validators = [validators.validate_ip_address4] 1024 981 1025 def __init__(self, *args, **kwargs): 982 1026 kwargs['max_length'] = 15 983 1027 Field.__init__(self, *args, **kwargs) … … class IPAddressField(Field): 988 1032 def get_internal_type(self): 989 1033 return "IPAddressField" 990 1034 991 def validate(self, field_data, all_data):992 validators.isValidIPAddress4(field_data, None)993 994 1035 def formfield(self, **kwargs): 995 1036 defaults = {'form_class': forms.IPAddressField} 996 1037 defaults.update(kwargs) … … class NullBooleanField(Field): 1030 1071 return super(NullBooleanField, self).formfield(**defaults) 1031 1072 1032 1073 class PhoneNumberField(Field): 1074 validators = [validators.validate_phone_number] 1075 1033 1076 def get_manipulator_field_objs(self): 1034 1077 return [oldforms.PhoneNumberField] 1035 1078 1036 1079 def get_internal_type(self): 1037 1080 return "PhoneNumberField" 1038 1081 1039 def validate(self, field_data, all_data):1040 validators.isValidPhone(field_data, all_data)1041 1042 1082 def formfield(self, **kwargs): 1043 1083 from django.contrib.localflavor.us.forms import USPhoneNumberField 1044 1084 defaults = {'form_class': USPhoneNumberField} … … class PositiveSmallIntegerField(IntegerField): 1070 1110 return super(PositiveSmallIntegerField, self).formfield(**defaults) 1071 1111 1072 1112 class SlugField(CharField): 1113 validators = [validators.validate_slug] 1073 1114 def __init__(self, *args, **kwargs): 1074 1115 kwargs['max_length'] = kwargs.get('max_length', 50) 1075 kwargs.setdefault('validator_list', []).append(validators.isSlug)1076 1116 # Set db_index=True unless it's been set manually. 1077 1117 if 'db_index' not in kwargs: 1078 1118 kwargs['db_index'] = True … … class URLField(CharField): 1168 1208 def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): 1169 1209 kwargs['max_length'] = kwargs.get('max_length', 200) 1170 1210 if verify_exists: 1171 kwargs.setdefault('validator _list', []).append(validators.isExistingURL)1211 kwargs.setdefault('validators', []).append(validators.validate_existing_url) 1172 1212 self.verify_exists = verify_exists 1173 1213 CharField.__init__(self, verbose_name, name, **kwargs) 1174 1214 -
django/db/models/fields/related.py
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index e814198..60fe8d3 100644
a b class ManyToManyField(RelatedField, Field): 830 830 objects = mod._default_manager.in_bulk(pks) 831 831 if len(objects) != len(pks): 832 832 badkeys = [k for k in pks if k not in objects] 833 raise validator s.ValidationError, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.",833 raise validator_list.ValidationError, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.", 834 834 "Please enter valid %(self)s IDs. The values %(value)r are invalid.", len(badkeys)) % { 835 835 'self': self.verbose_name, 836 836 'value': len(badkeys) == 1 and badkeys[0] or tuple(badkeys), -
django/forms/__init__.py
diff --git a/django/forms/__init__.py b/django/forms/__init__.py index 0d9c68f..8321417 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 from formsets import * -
django/forms/fields.py
diff --git a/django/forms/fields.py b/django/forms/fields.py index 47ae5e1..904849c 100644
a b except NameError: 25 25 26 26 from django.utils.translation import ugettext_lazy as _ 27 27 from django.utils.encoding import smart_unicode, smart_str 28 from django.core.exceptions import ValidationError 29 from django.core import validators 28 30 29 from util import ErrorList, ValidationError30 31 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput 32 from util import ErrorList 31 33 from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile 32 34 33 35 __all__ = ( … … EMPTY_VALUES = (None, '') 47 49 48 50 class Field(object): 49 51 widget = TextInput # Default widget to use when rendering this type of Field. 52 validators = [] 50 53 hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden". 51 54 default_error_messages = { 52 55 'required': _(u'This field is required.'), … … class Field(object): 57 60 creation_counter = 0 58 61 59 62 def __init__(self, required=True, widget=None, label=None, initial=None, 60 help_text=None, error_messages=None ):63 help_text=None, error_messages=None, validators=[]): 61 64 # required -- Boolean that specifies whether the field is required. 62 65 # True by default. 63 66 # widget -- A Widget class, or instance of a Widget class, that should … … class Field(object): 71 74 # initial -- A value to use in this Field's initial display. This value 72 75 # is *not* used as a fallback if data isn't given. 73 76 # help_text -- An optional string to use as "help text" for this Field. 77 # validators -- Optional list of additional validator functions 74 78 if label is not None: 75 79 label = smart_unicode(label) 80 self.validators = self.validators + validators 76 81 self.required, self.label, self.initial = required, label, initial 77 82 if help_text is None: 78 83 self.help_text = u'' … … class Field(object): 103 108 messages.update(error_messages or {}) 104 109 self.error_messages = messages 105 110 111 def to_python(self, value): 112 if value in EMPTY_VALUES: 113 return None 114 return smart_unicode(value) 115 116 def validate(self, value): 117 if self.required and value in EMPTY_VALUES: 118 raise ValidationError(self.error_messages['required']) 119 elif value in EMPTY_VALUES: 120 return 121 elist = ErrorList() 122 for validator in self.validators: 123 try: 124 validator(value, self.error_messages) 125 except ValidationError, e: 126 elist.extend(e.messages) 127 if elist: 128 raise ValidationError(elist) 129 106 130 def clean(self, value): 107 131 """ 108 132 Validates the given value and returns its "cleaned" value as an … … class Field(object): 110 134 111 135 Raises ValidationError for any errors. 112 136 """ 113 if self.required and value in EMPTY_VALUES:114 raise ValidationError(self.error_messages['required'])137 value = self.to_python(value) 138 self.validate(value) 115 139 return value 116 140 117 141 def widget_attrs(self, widget): … … class CharField(Field): 138 162 self.max_length, self.min_length = max_length, min_length 139 163 super(CharField, self).__init__(*args, **kwargs) 140 164 141 def clean(self, value): 142 "Validates max_length and min_length. Returns a Unicode object." 143 super(CharField, self).clean(value) 165 def to_python(self, value): 144 166 if value in EMPTY_VALUES: 145 167 return u'' 146 value = smart_unicode(value) 168 return smart_unicode(value) 169 170 def validate(self, value): 171 "Validates max_length and min_length. Returns a Unicode object." 172 super(CharField, self).validate(value) 147 173 value_length = len(value) 174 if value_length == 0 and not self.required: 175 return 148 176 if self.max_length is not None and value_length > self.max_length: 149 177 raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length}) 150 178 if self.min_length is not None and value_length < self.min_length: 151 179 raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length}) 152 return value153 180 154 181 def widget_attrs(self, widget): 155 182 if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)): … … class IntegerField(Field): 167 194 self.max_value, self.min_value = max_value, min_value 168 195 super(IntegerField, self).__init__(*args, **kwargs) 169 196 170 def clean(self, value): 171 """ 172 Validates that int() can be called on the input. Returns the result 173 of int(). Returns None for empty values. 174 """ 175 super(IntegerField, self).clean(value) 197 def to_python(self, value): 176 198 if value in EMPTY_VALUES: 177 199 return None 178 200 try: 179 value = int(str(value))201 return int(smart_str(value)) 180 202 except (ValueError, TypeError): 181 203 raise ValidationError(self.error_messages['invalid']) 204 205 def validate(self, value): 206 """ 207 Validates that int() can be called on the input. Returns the result 208 of int(). Returns None for empty values. 209 """ 210 super(IntegerField, self).validate(value) 211 if value is None: return 182 212 if self.max_value is not None and value > self.max_value: 183 213 raise ValidationError(self.error_messages['max_value'] % self.max_value) 184 214 if self.min_value is not None and value < self.min_value: 185 215 raise ValidationError(self.error_messages['min_value'] % self.min_value) 186 return value187 216 188 217 class FloatField(Field): 189 218 default_error_messages = { … … class FloatField(Field): 196 225 self.max_value, self.min_value = max_value, min_value 197 226 Field.__init__(self, *args, **kwargs) 198 227 199 def clean(self, value):228 def to_python(self, value): 200 229 """ 201 230 Validates that float() can be called on the input. Returns a float. 202 231 Returns None for empty values. 203 232 """ 204 super(FloatField, self).clean(value) 205 if not self.required and value in EMPTY_VALUES: 233 if value in EMPTY_VALUES: 206 234 return None 207 235 try: 208 value =float(value)236 return float(value) 209 237 except (ValueError, TypeError): 210 238 raise ValidationError(self.error_messages['invalid']) 239 240 def validate(self, value): 241 super(FloatField, self).validate(value) 242 if value is None: return 211 243 if self.max_value is not None and value > self.max_value: 212 244 raise ValidationError(self.error_messages['max_value'] % self.max_value) 213 245 if self.min_value is not None and value < self.min_value: 214 246 raise ValidationError(self.error_messages['min_value'] % self.min_value) 215 return value216 247 217 248 class DecimalField(Field): 218 249 default_error_messages = { … … class DecimalField(Field): 229 260 self.max_digits, self.decimal_places = max_digits, decimal_places 230 261 Field.__init__(self, *args, **kwargs) 231 262 232 def clean(self, value):263 def to_python(self, value): 233 264 """ 234 265 Validates that the input is a decimal number. Returns a Decimal 235 266 instance. Returns None for empty values. Ensures that there are no more 236 267 than max_digits in the number, and no more than decimal_places digits 237 268 after the decimal point. 238 269 """ 239 super(DecimalField, self).clean(value) 240 if not self.required and value in EMPTY_VALUES: 270 if value in EMPTY_VALUES: 241 271 return None 242 272 value = smart_str(value).strip() 243 273 try: 244 value =Decimal(value)274 return Decimal(value) 245 275 except DecimalException: 246 276 raise ValidationError(self.error_messages['invalid']) 277 278 def validate(self, value): 279 super(DecimalField, self).validate(value) 280 if value is None: return 247 281 pieces = str(value).lstrip("-").split('.') 248 282 decimals = (len(pieces) == 2) and len(pieces[1]) or 0 249 283 digits = len(pieces[0]) … … class DecimalField(Field): 257 291 raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places) 258 292 if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places): 259 293 raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) 260 return value261 294 262 295 DEFAULT_DATE_INPUT_FORMATS = ( 263 296 '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' … … class DateField(Field): 276 309 super(DateField, self).__init__(*args, **kwargs) 277 310 self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS 278 311 279 def clean(self, value):312 def to_python(self, value): 280 313 """ 281 314 Validates that the input can be converted to a date. Returns a Python 282 315 datetime.date object. 283 316 """ 284 super(DateField, self).clean(value)285 317 if value in EMPTY_VALUES: 286 318 return None 287 319 if isinstance(value, datetime.datetime): … … class TimeField(Field): 309 341 super(TimeField, self).__init__(*args, **kwargs) 310 342 self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS 311 343 312 def clean(self, value):344 def to_python(self, value): 313 345 """ 314 346 Validates that the input can be converted to a time. Returns a Python 315 347 datetime.time object. 316 348 """ 317 super(TimeField, self).clean(value)318 349 if value in EMPTY_VALUES: 319 350 return None 320 351 if isinstance(value, datetime.time): … … class DateTimeField(Field): 348 379 super(DateTimeField, self).__init__(*args, **kwargs) 349 380 self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS 350 381 351 def clean(self, value):382 def to_python(self, value): 352 383 """ 353 384 Validates that the input can be converted to a datetime. Returns a 354 385 Python datetime.datetime object. 355 386 """ 356 super(DateTimeField, self).clean(value)357 387 if value in EMPTY_VALUES: 358 388 return None 359 389 if isinstance(value, datetime.datetime): … … class RegexField(CharField): 390 420 regex = re.compile(regex) 391 421 self.regex = regex 392 422 393 def clean(self, value):423 def validate(self, value): 394 424 """ 395 425 Validates that the input matches the regular expression. Returns a 396 426 Unicode object. 397 427 """ 398 value = super(RegexField, self).clean(value)428 super(RegexField, self).validate(value) 399 429 if value == u'': 400 return value430 return 401 431 if not self.regex.search(value): 402 432 raise ValidationError(self.error_messages['invalid']) 403 return value404 433 405 434 email_re = re.compile( 406 435 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom 407 436 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string 408 437 r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain 409 438 410 class EmailField( RegexField):439 class EmailField(CharField): 411 440 default_error_messages = { 412 441 'invalid': _(u'Enter a valid e-mail address.'), 413 442 } 414 415 def __init__(self, max_length=None, min_length=None, *args, **kwargs): 416 RegexField.__init__(self, email_re, max_length, min_length, *args, 417 **kwargs) 443 validators = [validators.validate_email] 418 444 419 445 try: 420 446 from django.conf import settings … … class FileField(Field): 428 454 widget = FileInput 429 455 default_error_messages = { 430 456 'invalid': _(u"No file was submitted. Check the encoding type on the form."), 431 'missing': _(u"No file was submitted."),432 457 'empty': _(u"The submitted file is empty."), 433 458 } 434 459 435 def __init__(self, *args, **kwargs): 436 super(FileField, self).__init__(*args, **kwargs) 437 438 def clean(self, data, initial=None): 439 super(FileField, self).clean(initial or data) 460 def to_python(self, data, initial=None): 440 461 if not self.required and data in EMPTY_VALUES: 441 462 return None 442 463 elif not data and initial: … … class FileField(Field): 450 471 category = DeprecationWarning, 451 472 stacklevel = 2 452 473 ) 474 if not data: 475 raise ValidationError(self.error_messages['invalid']) 453 476 data = UploadedFile(data['filename'], data['content']) 454 477 455 478 try: … … class FileField(Field): 462 485 raise ValidationError(self.error_messages['invalid']) 463 486 if not file_size: 464 487 raise ValidationError(self.error_messages['empty']) 465 466 488 return data 467 489 490 def clean(self, value, initial=None): 491 "overriden clean to provide extra argument initial" 492 value = self.to_python(value, initial) 493 self.validate(value) 494 return value 495 468 496 class ImageField(FileField): 469 497 default_error_messages = { 470 498 'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."), 471 499 } 472 500 473 def clean(self, data, initial=None): 474 """ 475 Checks that the file-upload field data contains a valid image (GIF, JPG, 476 PNG, possibly others -- whatever the Python Imaging Library supports). 477 """ 478 f = super(ImageField, self).clean(data, initial) 479 if f is None: 480 return None 481 elif not data and initial: 482 return initial 501 def validate(self, data): 502 super(ImageField, self).validate(data) 503 if data is None: 504 return 483 505 from PIL import Image 484 485 506 # We need to get a file object for PIL. We might have a path or we might 486 507 # have to read the data into memory. 487 508 if hasattr(data, 'temporary_file_path'): … … class ImageField(FileField): 489 510 else: 490 511 if hasattr(data, 'read'): 491 512 file = StringIO(data.read()) 513 elif isinstance(data, UploadedFile): 514 file = StringIO(data.data.read()) 515 elif hasattr(data, 'seek') and callable(data.seek): 516 data.seek(0) 517 file = data 492 518 else: 493 file = StringIO(data['content'])519 file = data 494 520 495 521 try: 496 522 # load() is the only method that can spot a truncated JPEG, … … class ImageField(FileField): 514 540 raise 515 541 except Exception: # Python Imaging Library doesn't recognize it as an image 516 542 raise ValidationError(self.error_messages['invalid_image']) 517 if hasattr(f, 'seek') and callable(f.seek):518 f.seek(0)519 return f520 543 521 544 url_re = re.compile( 522 545 r'^https?://' # http:// or https:// … … class URLField(RegexField): 539 562 self.verify_exists = verify_exists 540 563 self.user_agent = validator_user_agent 541 564 542 def clean(self, value): 565 def to_python(self, value): 566 value = super(URLField, self).to_python(value) 543 567 # If no URL scheme given, assume http:// 544 568 if value and '://' not in value: 545 569 value = u'http://%s' % value 546 570 # If no URL path given, assume / 547 571 if value and not urlparse.urlsplit(value)[2]: 548 572 value += '/' 549 value = super(URLField, self).clean(value) 573 return value 574 575 def validate(self, value): 576 super(URLField, self).validate(value) 550 577 if value == u'': 551 return value578 return 552 579 if self.verify_exists: 553 import urllib2 554 headers = { 555 "Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", 556 "Accept-Language": "en-us,en;q=0.5", 557 "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7", 558 "Connection": "close", 559 "User-Agent": self.user_agent, 560 } 561 try: 562 req = urllib2.Request(value, None, headers) 563 u = urllib2.urlopen(req) 564 except ValueError: 565 raise ValidationError(self.error_messages['invalid']) 566 except: # urllib2.URLError, httplib.InvalidURL, etc. 567 raise ValidationError(self.error_messages['invalid_link']) 568 return value 580 # we cannot put this in self.validators because its conditional 581 validators.validate_existing_url(value, self.error_messages) 569 582 570 583 class BooleanField(Field): 571 584 widget = CheckboxInput 572 585 573 def clean(self, value):586 def to_python(self, value): 574 587 """Returns a Python boolean object.""" 575 588 # Explicitly check for the string 'False', which is what a hidden field 576 589 # will submit for False. Because bool("True") == True, we don't need to … … class BooleanField(Field): 579 592 value = False 580 593 else: 581 594 value = bool(value) 582 super(BooleanField, self).clean(value)583 if not value and self.required:584 raise ValidationError(self.error_messages['required'])585 595 return value 586 596 597 def validate(self, value): 598 if self.required and not value: 599 raise ValidationError(self.error_messages['required']) 600 601 587 602 class NullBooleanField(BooleanField): 588 603 """ 589 604 A field whose valid values are None, True and False. Invalid values are 590 605 cleaned to None. 606 607 Note that validation doesn't apply here. 591 608 """ 592 609 widget = NullBooleanSelect 593 610 594 def clean(self, value):611 def to_python(self, value): 595 612 return {True: True, False: False}.get(value, None) 596 613 614 def validate(self, value): 615 pass 616 617 597 618 class ChoiceField(Field): 598 619 widget = Select 599 620 default_error_messages = { … … class ChoiceField(Field): 617 638 618 639 choices = property(_get_choices, _set_choices) 619 640 620 def clean(self, value): 621 """ 622 Validates that the input is in self.choices. 623 """ 624 value = super(ChoiceField, self).clean(value) 625 if value in EMPTY_VALUES: 626 value = u'' 627 value = smart_unicode(value) 628 if value == u'': 629 return value 641 def validate(self, value): 642 super(ChoiceField, self).validate(value) 643 if value is None and not self.required: 644 return 630 645 if not self.valid_value(value): 631 646 raise ValidationError(self.error_messages['invalid_choice'] % {'value': value}) 632 return value633 647 634 648 def valid_value(self, value): 635 649 "Check to see if the provided value is a valid choice" … … class MultipleChoiceField(ChoiceField): 652 666 'invalid_list': _(u'Enter a list of values.'), 653 667 } 654 668 655 def clean(self, value):669 def to_python(self, value): 656 670 """ 657 671 Validates that the input is a list or tuple. 658 672 """ 659 if self.required and not value: 660 raise ValidationError(self.error_messages['required']) 661 elif not self.required and not value: 673 if not value: 662 674 return [] 663 675 if not isinstance(value, (list, tuple)): 664 676 raise ValidationError(self.error_messages['invalid_list']) 665 new_value = [smart_unicode(val) for val in value] 677 return [smart_unicode(val) for val in value] 678 679 def validate(self, value): 666 680 # Validate that each value in the value list is in self.choices. 667 for val in new_value: 681 if self.required and value == []: 682 raise ValidationError(self.error_messages['required']) 683 for val in value: 668 684 if not self.valid_value(val): 669 685 raise ValidationError(self.error_messages['invalid_choice'] % {'value': val}) 670 return new_value671 686 672 687 class ComboField(Field): 673 688 """ … … class ComboField(Field): 682 697 f.required = False 683 698 self.fields = fields 684 699 685 def clean(self, value): 700 def to_python(self, value): 701 for field in self.fields: 702 value = field.to_python(value) 703 return value 704 705 def validate(self, value): 686 706 """ 687 707 Validates the given value against all of self.fields, which is a 688 708 list of Field instances. 689 709 """ 690 super(ComboField, self). clean(value)710 super(ComboField, self).validate(value) 691 711 for field in self.fields: 692 value = field.clean(value) 693 return value 712 field.validate(value) 694 713 695 714 class MultiValueField(Field): 696 715 """ … … class MultiValueField(Field): 722 741 f.required = False 723 742 self.fields = fields 724 743 725 def clean(self, value):744 def to_python(self, value): 726 745 """ 727 746 Validates every value in the given list. A value is validated against 728 747 the corresponding Field in self.fields. … … class MultiValueField(Field): 736 755 if not value or isinstance(value, (list, tuple)): 737 756 if not value or not [v for v in value if v not in EMPTY_VALUES]: 738 757 if self.required: 739 r aise ValidationError(self.error_messages['required'])758 return None 740 759 else: 741 760 return self.compress([]) 742 761 else: 743 762 raise ValidationError(self.error_messages['invalid']) 763 744 764 for i, field in enumerate(self.fields): 745 765 try: 746 766 field_value = value[i] … … class SplitDateTimeField(MultiValueField): 824 844 return datetime.datetime.combine(*data_list) 825 845 return None 826 846 827 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}$') 828 829 class IPAddressField(RegexField): 847 class IPAddressField(CharField): 830 848 default_error_messages = { 831 849 'invalid': _(u'Enter a valid IPv4 address.'), 832 850 } 833 834 def __init__(self, *args, **kwargs): 835 super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs) 851 validators = [validators.validate_ip_address4] -
django/forms/forms.py
diff --git a/django/forms/forms.py b/django/forms/forms.py index 753ee25..05936f2 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.forms import ValidationError, NON_FIELD_ERRORS 11 12 12 13 from fields import Field, FileField 13 14 from widgets import Media, media_property, 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): 217 217 else: 218 218 value = field.clean(value) 219 219 self.cleaned_data[name] = value 220 # FIXME deprecated - keeping this here for backwards compatibility 220 221 if hasattr(self, 'clean_%s' % name): 221 222 value = getattr(self, 'clean_%s' % name)() 222 223 self.cleaned_data[name] = value 224 225 if hasattr(self, 'validate_%s' % name): 226 getattr(self, 'validate_%s' % name)(value) 223 227 except ValidationError, e: 224 self._errors[name] = e.messages228 self._errors[name] = ErrorList(e.messages) 225 229 if name in self.cleaned_data: 226 230 del self.cleaned_data[name] 227 231 try: 228 self. cleaned_data = self.clean()232 self.validate() 229 233 except ValidationError, e: 230 self._errors[NON_FIELD_ERRORS] = e.messages 234 if hasattr(e, 'message_dict'): 235 for k, v in e.message_dict.items(): 236 self._errors.setdefault(k, []).extend(v) 237 else: 238 self._errors[NON_FIELD_ERRORS] = ErrorList(e.messages) 231 239 if self._errors: 232 240 delattr(self, 'cleaned_data') 233 241 234 242 def clean(self): 235 243 """ 244 FIXME: deprecated, use validate() instead 245 236 246 Hook for doing any extra form-wide cleaning after Field.clean() been 237 247 called on every field. Any ValidationError raised by this method will 238 248 not be associated with a particular field; it will have a special-case … … class BaseForm(StrAndUnicode): 274 284 return media 275 285 media = property(_get_media) 276 286 287 def validate(self): 288 self.cleaned_data = self.clean() 289 277 290 def is_multipart(self): 278 291 """ 279 292 Returns True if the form needs to be multipart-encrypted, i.e. it has -
django/forms/formsets.py
diff --git a/django/forms/formsets.py b/django/forms/formsets.py index 2f13bf5..a0a9199 100644
a b from django.utils.encoding import StrAndUnicode 3 3 from django.utils.safestring import mark_safe 4 4 from fields import IntegerField, BooleanField 5 5 from widgets import Media, HiddenInput 6 from util import ErrorList, ValidationError 6 from django.core.exceptions import ValidationError 7 from util import ErrorList 7 8 8 9 __all__ = ('BaseFormSet', 'all_valid') 9 10 -
django/forms/models.py
diff --git a/django/forms/models.py b/django/forms/models.py index 1f807f2..da9c4f0 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, ValidationError 12 from django.forms.util import ErrorList 11 13 12 from util import ValidationError, ErrorList13 14 from forms import BaseForm, get_declared_fields 14 15 from fields import Field, ChoiceField, IntegerField, EMPTY_VALUES 15 16 from widgets import Select, SelectMultiple, HiddenInput, MultipleHiddenInput … … class BaseModelForm(BaseForm): 262 263 super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data, 263 264 error_class, label_suffix, empty_permitted) 264 265 266 def validate(self): 267 super(BaseModelForm, self).validate() 268 if self._errors: 269 return 270 self.instance.clean(self.cleaned_data) 271 265 272 def save(self, commit=True): 266 273 """ 267 274 Saves this ``form``'s cleaned_data into model instance … … class BaseInlineFormset(BaseModelFormSet): 410 417 # is there a better way to get the object descriptor? 411 418 self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name() 412 419 super(BaseInlineFormset, self).__init__(data, files, prefix=prefix or self.rel_name) 420 421 def _construct_form(self, i, **kwargs): 422 form = super(BaseInlineFormset, self)._construct_form(i, **kwargs) 423 setattr(form.instance, self.fk.get_attname(), self.instance.pk) 424 return form 413 425 414 426 def _construct_forms(self): 415 427 if self.save_as_new: … … class ModelChoiceField(ChoiceField): 572 584 573 585 choices = property(_get_choices, ChoiceField._set_choices) 574 586 575 def clean(self, value): 576 Field.clean(self, value) 577 if value in EMPTY_VALUES: 587 def to_python(self, value): 588 if self.required and value in EMPTY_VALUES: 589 raise ValidationError(self.error_messages['required']) 590 elif value in EMPTY_VALUES: 578 591 return None 579 592 try: 580 593 value = self.queryset.get(pk=value) … … class ModelChoiceField(ChoiceField): 582 595 raise ValidationError(self.error_messages['invalid_choice']) 583 596 return value 584 597 598 def validate(self, value): 599 pass 600 585 601 class ModelMultipleChoiceField(ModelChoiceField): 586 602 """A MultipleChoiceField whose choices are a model QuerySet.""" 587 603 hidden_widget = MultipleHiddenInput … … class ModelMultipleChoiceField(ModelChoiceField): 598 614 cache_choices, required, widget, label, initial, help_text, 599 615 *args, **kwargs) 600 616 601 def clean(self, value):617 def to_python(self, value): 602 618 if self.required and not value: 603 619 raise ValidationError(self.error_messages['required']) 604 620 elif not self.required and not value: … … class ModelMultipleChoiceField(ModelChoiceField): 614 630 else: 615 631 final_values.append(obj) 616 632 return final_values 633 -
django/forms/util.py
diff --git a/django/forms/util.py b/django/forms/util.py index 3d80ad2..6355949 100644
a b class ErrorList(list, StrAndUnicode): 36 36 def __unicode__(self): 37 37 return self.as_ul() 38 38 39 def __repr__(self): 40 return repr([force_unicode(e) for e in self]) 41 39 42 def as_ul(self): 40 43 if not self: return u'' 41 44 return mark_safe(u'<ul class="errorlist">%s</ul>' … … class ErrorList(list, StrAndUnicode): 44 47 def as_text(self): 45 48 if not self: return u'' 46 49 return u'\n'.join([u'* %s' % force_unicode(e) for e in self]) 47 48 def __repr__(self):49 return repr([force_unicode(e) for e in self])50 51 class ValidationError(Exception):52 def __init__(self, message):53 """54 ValidationError can be passed any object that can be printed (usually55 a string) or a list of objects.56 """57 if isinstance(message, list):58 self.messages = ErrorList([smart_unicode(msg) for msg in message])59 else:60 message = smart_unicode(message)61 self.messages = ErrorList([message])62 63 def __str__(self):64 # This is needed because, without a __str__(), printing an exception65 # instance would result in this:66 # AttributeError: ValidationError instance has no attribute 'args'67 # See http://www.python.org/doc/current/tut/node10.html#handling68 return repr(self.messages) -
django/newforms/__init__.py
diff --git a/django/newforms/__init__.py b/django/newforms/__init__.py index 5f319f8..b437d84 100644
a b warnings.warn( 4 4 message = "django.newforms is no longer new. Import django.forms instead.", 5 5 stacklevel = 2 6 6 ) 7 from django.forms import * 8 No newline at end of file 7 from django.forms import * -
django/oldforms/__init__.py
diff --git a/django/oldforms/__init__.py b/django/oldforms/__init__.py index b5698ab..b9f7204 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..7500347
- + 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 try: 146 date(year, month, day) 147 except ValueError, e: 148 msg = _('Invalid date: %s') % _(str(e)) 149 raise ValidationError, msg 150 151 def isValidANSIDate(field_data, all_data): 152 # DONE 153 if not ansi_date_re.search(field_data): 154 raise ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 155 _isValidDate(field_data) 156 157 def isValidANSITime(field_data, all_data): 158 # DONE 159 if not ansi_time_re.search(field_data): 160 raise ValidationError, _('Enter a valid time in HH:MM format.') 161 162 def isValidANSIDatetime(field_data, all_data): 163 # DONE 164 if not ansi_datetime_re.search(field_data): 165 raise ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 166 _isValidDate(field_data.split()[0]) 167 168 def isValidEmail(field_data, all_data): 169 # DONE 170 if not email_re.search(field_data): 171 raise ValidationError, _('Enter a valid e-mail address.') 172 173 def isValidImage(field_data, all_data): 174 """ 175 Checks that the file-upload field data contains a valid image (GIF, JPG, 176 PNG, possibly others -- whatever the Python Imaging Library supports). 177 """ 178 from PIL import Image 179 from cStringIO import StringIO 180 try: 181 content = field_data.read() 182 except TypeError: 183 raise ValidationError, _("No file was submitted. Check the encoding type on the form.") 184 try: 185 # load() is the only method that can spot a truncated JPEG, 186 # but it cannot be called sanely after verify() 187 trial_image = Image.open(StringIO(content)) 188 trial_image.load() 189 # verify() is the only method that can spot a corrupt PNG, 190 # but it must be called immediately after the constructor 191 trial_image = Image.open(StringIO(content)) 192 trial_image.verify() 193 except Exception: # Python Imaging Library doesn't recognize it as an image 194 raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.") 195 196 def isValidImageURL(field_data, all_data): 197 uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png')) 198 try: 199 uc(field_data, all_data) 200 except URLMimeTypeCheck.InvalidContentType: 201 raise ValidationError, _("The URL %s does not point to a valid image.") % field_data 202 203 def isValidPhone(field_data, all_data): 204 if not phone_re.search(field_data): 205 raise ValidationError, _('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data 206 207 def isValidQuicktimeVideoURL(field_data, all_data): 208 "Checks that the given URL is a video that can be played by QuickTime (qt, mpeg)" 209 uc = URLMimeTypeCheck(('video/quicktime', 'video/mpeg',)) 210 try: 211 uc(field_data, all_data) 212 except URLMimeTypeCheck.InvalidContentType: 213 raise ValidationError, _("The URL %s does not point to a valid QuickTime video.") % field_data 214 215 def isValidURL(field_data, all_data): 216 if not url_re.search(field_data): 217 raise ValidationError, _("A valid URL is required.") 218 219 def isValidHTML(field_data, all_data): 220 import urllib, urllib2 221 try: 222 u = urllib2.urlopen('http://validator.w3.org/check', urllib.urlencode({'fragment': field_data, 'output': 'xml'})) 223 except: 224 # Validator or Internet connection is unavailable. Fail silently. 225 return 226 html_is_valid = (u.headers.get('x-w3c-validator-status', 'Invalid') == 'Valid') 227 if html_is_valid: 228 return 229 from xml.dom.minidom import parseString 230 error_messages = [e.firstChild.wholeText for e in parseString(u.read()).getElementsByTagName('messages')[0].getElementsByTagName('msg')] 231 raise ValidationError, _("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages) 232 233 def isWellFormedXml(field_data, all_data): 234 from xml.dom.minidom import parseString 235 try: 236 parseString(field_data) 237 except Exception, e: # Naked except because we're not sure what will be thrown 238 raise ValidationError, _("Badly formed XML: %s") % str(e) 239 240 def isWellFormedXmlFragment(field_data, all_data): 241 isWellFormedXml('<root>%s</root>' % field_data, all_data) 242 243 def isExistingURL(field_data, all_data): 244 try: 245 headers = { 246 "Accept" : "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", 247 "Accept-Language" : "en-us,en;q=0.5", 248 "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7", 249 "Connection" : "close", 250 "User-Agent": settings.URL_VALIDATOR_USER_AGENT 251 } 252 req = urllib2.Request(field_data,None, headers) 253 u = urllib2.urlopen(req) 254 except ValueError: 255 raise ValidationError, _("Invalid URL: %s") % field_data 256 except urllib2.HTTPError, e: 257 # 401s are valid; they just mean authorization is required. 258 # 301 and 302 are redirects; they just mean look somewhere else. 259 if str(e.code) not in ('401','301','302'): 260 raise ValidationError, _("The URL %s is a broken link.") % field_data 261 except: # urllib2.URLError, httplib.InvalidURL, etc. 262 raise ValidationError, _("The URL %s is a broken link.") % field_data 263 264 def isValidUSState(field_data, all_data): 265 "Checks that the given string is a valid two-letter U.S. state abbreviation" 266 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'] 267 if field_data.upper() not in states: 268 raise ValidationError, _("Enter a valid U.S. state abbreviation.") 269 270 def hasNoProfanities(field_data, all_data): 271 """ 272 Checks that the given string has no profanities in it. This does a simple 273 check for whether each profanity exists within the string, so 'fuck' will 274 catch 'motherfucker' as well. Raises a ValidationError such as: 275 Watch your mouth! The words "f--k" and "s--t" are not allowed here. 276 """ 277 field_data = field_data.lower() # normalize 278 words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data] 279 if words_seen: 280 from django.utils.text import get_text_list 281 plural = len(words_seen) 282 raise ValidationError, ungettext("Watch your mouth! The word %s is not allowed here.", 283 "Watch your mouth! The words %s are not allowed here.", plural) % \ 284 get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], _('and')) 285 286 class AlwaysMatchesOtherField(object): 287 def __init__(self, other_field_name, error_message=None): 288 self.other = other_field_name 289 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must match the '%s' field."), self.other) 290 self.always_test = True 291 292 def __call__(self, field_data, all_data): 293 if field_data != all_data[self.other]: 294 raise ValidationError, self.error_message 295 296 class ValidateIfOtherFieldEquals(object): 297 def __init__(self, other_field, other_value, validator_list): 298 self.other_field, self.other_value = other_field, other_value 299 self.validator_list = validator_list 300 self.always_test = True 301 302 def __call__(self, field_data, all_data): 303 if self.other_field in all_data and all_data[self.other_field] == self.other_value: 304 for v in self.validator_list: 305 v(field_data, all_data) 306 307 class RequiredIfOtherFieldNotGiven(object): 308 def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter something for at least one field.")): 309 self.other, self.error_message = other_field_name, error_message 310 self.always_test = True 311 312 def __call__(self, field_data, all_data): 313 if not all_data.get(self.other, False) and not field_data: 314 raise ValidationError, self.error_message 315 316 class RequiredIfOtherFieldsGiven(object): 317 def __init__(self, other_field_names, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")): 318 self.other, self.error_message = other_field_names, error_message 319 self.always_test = True 320 321 def __call__(self, field_data, all_data): 322 for field in self.other: 323 if all_data.get(field, False) and not field_data: 324 raise ValidationError, self.error_message 325 326 class RequiredIfOtherFieldGiven(RequiredIfOtherFieldsGiven): 327 "Like RequiredIfOtherFieldsGiven, but takes a single field name instead of a list." 328 def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")): 329 RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message) 330 331 class RequiredIfOtherFieldEquals(object): 332 def __init__(self, other_field, other_value, error_message=None, other_label=None): 333 self.other_field = other_field 334 self.other_value = other_value 335 other_label = other_label or other_value 336 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is %(value)s"), { 337 'field': other_field, 'value': other_label}) 338 self.always_test = True 339 340 def __call__(self, field_data, all_data): 341 if self.other_field in all_data and all_data[self.other_field] == self.other_value and not field_data: 342 raise ValidationError(self.error_message) 343 344 class RequiredIfOtherFieldDoesNotEqual(object): 345 def __init__(self, other_field, other_value, other_label=None, error_message=None): 346 self.other_field = other_field 347 self.other_value = other_value 348 other_label = other_label or other_value 349 self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is not %(value)s"), { 350 'field': other_field, 'value': other_label}) 351 self.always_test = True 352 353 def __call__(self, field_data, all_data): 354 if self.other_field in all_data and all_data[self.other_field] != self.other_value and not field_data: 355 raise ValidationError(self.error_message) 356 357 class IsLessThanOtherField(object): 358 def __init__(self, other_field_name, error_message): 359 self.other, self.error_message = other_field_name, error_message 360 361 def __call__(self, field_data, all_data): 362 if field_data > all_data[self.other]: 363 raise ValidationError, self.error_message 364 365 class UniqueAmongstFieldsWithPrefix(object): 366 def __init__(self, field_name, prefix, error_message): 367 self.field_name, self.prefix = field_name, prefix 368 self.error_message = error_message or ugettext_lazy("Duplicate values are not allowed.") 369 370 def __call__(self, field_data, all_data): 371 for field_name, value in all_data.items(): 372 if field_name != self.field_name and value == field_data: 373 raise ValidationError, self.error_message 374 375 class NumberIsInRange(object): 376 """ 377 Validator that tests if a value is in a range (inclusive). 378 """ 379 def __init__(self, lower=None, upper=None, error_message=''): 380 self.lower, self.upper = lower, upper 381 if not error_message: 382 if lower and upper: 383 self.error_message = _("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper} 384 elif lower: 385 self.error_message = _("This value must be at least %s.") % lower 386 elif upper: 387 self.error_message = _("This value must be no more than %s.") % upper 388 else: 389 self.error_message = error_message 390 391 def __call__(self, field_data, all_data): 392 # Try to make the value numeric. If this fails, we assume another 393 # validator will catch the problem. 394 try: 395 val = float(field_data) 396 except ValueError: 397 return 398 399 # Now validate 400 if self.lower and self.upper and (val < self.lower or val > self.upper): 401 raise ValidationError(self.error_message) 402 elif self.lower and val < self.lower: 403 raise ValidationError(self.error_message) 404 elif self.upper and val > self.upper: 405 raise ValidationError(self.error_message) 406 407 class IsAPowerOf(object): 408 """ 409 Usage: If you create an instance of the IsPowerOf validator: 410 v = IsAPowerOf(2) 411 412 The following calls will succeed: 413 v(4, None) 414 v(8, None) 415 v(16, None) 416 417 But this call: 418 v(17, None) 419 will raise "django.core.validators.ValidationError: ['This value must be a power of 2.']" 420 """ 421 def __init__(self, power_of): 422 self.power_of = power_of 423 424 def __call__(self, field_data, all_data): 425 from math import log 426 val = log(int(field_data)) / log(self.power_of) 427 if val != int(val): 428 raise ValidationError, _("This value must be a power of %s.") % self.power_of 429 430 class IsValidDecimal(object): 431 def __init__(self, max_digits, decimal_places): 432 self.max_digits, self.decimal_places = max_digits, decimal_places 433 434 def __call__(self, field_data, all_data): 435 try: 436 val = Decimal(field_data) 437 except DecimalException: 438 raise ValidationError, _("Please enter a valid decimal number.") 439 440 pieces = str(val).lstrip("-").split('.') 441 decimals = (len(pieces) == 2) and len(pieces[1]) or 0 442 digits = len(pieces[0]) 443 444 if digits + decimals > self.max_digits: 445 raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.", 446 "Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits 447 if digits > (self.max_digits - self.decimal_places): 448 raise ValidationError, ungettext( "Please enter a valid decimal number with a whole part of at most %s digit.", 449 "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) 450 if decimals > self.decimal_places: 451 raise ValidationError, ungettext("Please enter a valid decimal number with at most %s decimal place.", 452 "Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places 453 454 def isValidFloat(field_data, all_data): 455 data = smart_str(field_data) 456 try: 457 float(data) 458 except ValueError: 459 raise ValidationError, _("Please enter a valid floating point number.") 460 461 class HasAllowableSize(object): 462 """ 463 Checks that the file-upload field data is a certain size. min_size and 464 max_size are measurements in bytes. 465 """ 466 def __init__(self, min_size=None, max_size=None, min_error_message=None, max_error_message=None): 467 self.min_size, self.max_size = min_size, max_size 468 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) 469 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) 470 471 def __call__(self, field_data, all_data): 472 try: 473 content = field_data.read() 474 except TypeError: 475 raise ValidationError, ugettext_lazy("No file was submitted. Check the encoding type on the form.") 476 if self.min_size is not None and len(content) < self.min_size: 477 raise ValidationError, self.min_error_message 478 if self.max_size is not None and len(content) > self.max_size: 479 raise ValidationError, self.max_error_message 480 481 class MatchesRegularExpression(object): 482 """ 483 Checks that the field matches the given regular-expression. The regex 484 should be in string format, not already compiled. 485 """ 486 def __init__(self, regexp, error_message=ugettext_lazy("The format for this field is wrong.")): 487 self.regexp = re.compile(regexp) 488 self.error_message = error_message 489 490 def __call__(self, field_data, all_data): 491 if not self.regexp.search(field_data): 492 raise ValidationError(self.error_message) 493 494 class AnyValidator(object): 495 """ 496 This validator tries all given validators. If any one of them succeeds, 497 validation passes. If none of them succeeds, the given message is thrown 498 as a validation error. The message is rather unspecific, so it's best to 499 specify one on instantiation. 500 """ 501 def __init__(self, validator_list=None, error_message=ugettext_lazy("This field is invalid.")): 502 if validator_list is None: validator_list = [] 503 self.validator_list = validator_list 504 self.error_message = error_message 505 for v in validator_list: 506 if hasattr(v, 'always_test'): 507 self.always_test = True 508 509 def __call__(self, field_data, all_data): 510 for v in self.validator_list: 511 try: 512 v(field_data, all_data) 513 return 514 except ValidationError, e: 515 pass 516 raise ValidationError(self.error_message) 517 518 class URLMimeTypeCheck(object): 519 "Checks that the provided URL points to a document with a listed mime type" 520 class CouldNotRetrieve(ValidationError): 521 pass 522 class InvalidContentType(ValidationError): 523 pass 524 525 def __init__(self, mime_type_list): 526 self.mime_type_list = mime_type_list 527 528 def __call__(self, field_data, all_data): 529 import urllib2 530 try: 531 isValidURL(field_data, all_data) 532 except ValidationError: 533 raise 534 try: 535 info = urllib2.urlopen(field_data).info() 536 except (urllib2.HTTPError, urllib2.URLError): 537 raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data 538 content_type = info['content-type'] 539 if content_type not in self.mime_type_list: 540 raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % { 541 'url': field_data, 'contenttype': content_type} 542 543 class RelaxNGCompact(object): 544 "Validate against a Relax NG compact schema" 545 def __init__(self, schema_path, additional_root_element=None): 546 self.schema_path = schema_path 547 self.additional_root_element = additional_root_element 548 549 def __call__(self, field_data, all_data): 550 import os, tempfile 551 if self.additional_root_element: 552 field_data = '<%(are)s>%(data)s\n</%(are)s>' % { 553 'are': self.additional_root_element, 554 'data': field_data 555 } 556 filename = tempfile.mktemp() # Insecure, but nothing else worked 557 fp = open(filename, 'w') 558 fp.write(field_data) 559 fp.close() 560 if not os.path.exists(settings.JING_PATH): 561 raise Exception, "%s not found!" % settings.JING_PATH 562 p = os.popen('%s -c %s %s' % (settings.JING_PATH, self.schema_path, filename)) 563 errors = [line.strip() for line in p.readlines()] 564 p.close() 565 os.unlink(filename) 566 display_errors = [] 567 lines = field_data.split('\n') 568 for error in errors: 569 ignored, line, level, message = error.split(':', 3) 570 # Scrape the Jing error messages to reword them more nicely. 571 m = re.search(r'Expected "(.*?)" to terminate element starting on line (\d+)', message) 572 if m: 573 display_errors.append(_('Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "%(start)s".)') % \ 574 {'tag':m.group(1).replace('/', ''), 'line':m.group(2), 'start':lines[int(m.group(2)) - 1][:30]}) 575 continue 576 if message.strip() == 'text not allowed here': 577 display_errors.append(_('Some text starting on line %(line)s is not allowed in that context. (Line starts with "%(start)s".)') % \ 578 {'line':line, 'start':lines[int(line) - 1][:30]}) 579 continue 580 m = re.search(r'\s*attribute "(.*?)" not allowed at this point; ignored', message) 581 if m: 582 display_errors.append(_('"%(attr)s" on line %(line)s is an invalid attribute. (Line starts with "%(start)s".)') % \ 583 {'attr':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 584 continue 585 m = re.search(r'\s*unknown element "(.*?)"', message) 586 if m: 587 display_errors.append(_('"<%(tag)s>" on line %(line)s is an invalid tag. (Line starts with "%(start)s".)') % \ 588 {'tag':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 589 continue 590 if message.strip() == 'required attributes missing': 591 display_errors.append(_('A tag on line %(line)s is missing one or more required attributes. (Line starts with "%(start)s".)') % \ 592 {'line':line, 'start':lines[int(line) - 1][:30]}) 593 continue 594 m = re.search(r'\s*bad value for attribute "(.*?)"', message) 595 if m: 596 display_errors.append(_('The "%(attr)s" attribute on line %(line)s has an invalid value. (Line starts with "%(start)s".)') % \ 597 {'attr':m.group(1), 'line':line, 'start':lines[int(line) - 1][:30]}) 598 continue 599 # Failing all those checks, use the default error message. 600 display_error = 'Line %s: %s [%s]' % (line, message, level.strip()) 601 display_errors.append(display_error) 602 if len(display_errors) > 0: 603 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 be2a8ba..9d8f4ea 100644
a b Create a new article, with categories, via the form. 487 487 ... model = Article 488 488 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01', 489 489 ... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) 490 >>> f.is_valid() 491 True 490 492 >>> new_art = f.save() 491 493 >>> new_art.id 492 494 2 … … u'...test2.txt' 861 863 >>> instance.delete() 862 864 863 865 # Test the non-required FileField 864 866 # It should fail since the field IS required on the model 865 867 >>> f = TextFileForm(data={'description': u'Assistance'}) 866 868 >>> f.fields['file'].required = False 867 869 >>> f.is_valid() 868 True 869 >>> instance = f.save() 870 >>> instance.file 871 '' 870 False 871 >>> f.errors 872 {'file': [u'This field is required.']} 872 873 873 874 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')}, instance=instance) 874 875 >>> f.is_valid() … … u'...test2.png' 970 971 >>> f = ImageFileForm(data={'description': u'Test'}) 971 972 >>> f.fields['image'].required = False 972 973 >>> f.is_valid() 973 True974 >>> instance = f.save()975 >>> instance.image 976 '' 974 False 975 >>> f.errors 976 {'image': [u'This field is required.']} 977 977 978 978 979 >>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)}, instance=instance) 979 980 >>> f.is_valid() -
tests/modeltests/validation/models.py
diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py index 7ed9d66..4d08650 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( )18 email = models.EmailField(unique=True) 19 19 best_time = models.TimeField() 20 20 21 class Meta: 22 unique_together = (('name', 'is_child'),) 21 23 def __unicode__(self): 22 24 return self.name 23 25 … … __test__ = {'API_TESTS':""" 32 34 ... 'email': 'john@example.com', 33 35 ... 'best_time': datetime.time(16, 20), 34 36 ... } 35 >>> p = Person(**valid_params) 36 >>> p.validate() 37 {} 38 39 >>> p = Person(**dict(valid_params, id='23')) 40 >>> p.validate() 41 {} 37 >>> p = Person(**dict(valid_params, email='john@e.com', name='Jack')) 38 >>> p.clean() 39 >>> p.save() 40 41 >>> p = Person(**dict(valid_params, email='john@e.com')) 42 >>> p.clean() 43 Traceback (most recent call last): 44 ... 45 ValidationError: {'email': [u'This field must be unique']} 46 47 >>> p = Person(**dict(valid_params, id='23', name='Jack')) 48 >>> p.clean() 49 Traceback (most recent call last): 50 ... 51 ValidationError: {'__all__': u'Fields name, is_child must be unique.'} 42 52 >>> p.id 43 53 23 44 54 45 >>> p = Person(**dict(valid_params, id='foo')) 46 >>> p.validate()['id'] 47 [u'This value must be an integer.'] 55 # when type coercion fails, no other validation is done 56 >>> p = Person(**dict(valid_params, email='john@e.com', id='foo')) 57 >>> p.clean() 58 Traceback (most recent call last): 59 ... 60 ValidationError: {'id': [u'This value must be an integer.']} 48 61 49 62 >>> p = Person(**dict(valid_params, id=None)) 50 >>> p.validate() 51 {} 63 >>> p.clean() 52 64 >>> repr(p.id) 53 65 'None' 54 66 55 67 >>> p = Person(**dict(valid_params, is_child='t')) 56 >>> p.validate() 57 {} 68 >>> p.clean() 58 69 >>> p.is_child 59 70 True 60 71 61 72 >>> p = Person(**dict(valid_params, is_child='f')) 62 >>> p.validate() 63 {} 73 >>> p.clean() 64 74 >>> p.is_child 65 75 False 66 76 67 77 >>> p = Person(**dict(valid_params, is_child=True)) 68 >>> p.validate() 69 {} 78 >>> p.clean() 70 79 >>> p.is_child 71 80 True 72 81 73 82 >>> p = Person(**dict(valid_params, is_child=False)) 74 >>> p.validate() 75 {} 83 >>> p.clean() 76 84 >>> p.is_child 77 85 False 78 86 79 87 >>> p = Person(**dict(valid_params, is_child='foo')) 80 >>> p.validate()['is_child'] 81 [u'This value must be either True or False.'] 88 >>> p.clean() 89 Traceback (most recent call last): 90 ... 91 ValidationError: {'is_child': [u'This value must be either True or False.']} 82 92 83 93 >>> p = Person(**dict(valid_params, name=u'Jose')) 84 >>> p.validate() 85 {} 94 >>> p.clean() 86 95 >>> p.name 87 96 u'Jose' 88 97 89 98 >>> p = Person(**dict(valid_params, name=227)) 90 >>> p.validate() 91 {} 99 >>> p.clean() 92 100 >>> p.name 93 101 u'227' 94 102 95 103 >>> p = Person(**dict(valid_params, birthdate=datetime.date(2000, 5, 3))) 96 >>> p.validate() 97 {} 104 >>> p.clean() 98 105 >>> p.birthdate 99 106 datetime.date(2000, 5, 3) 100 107 101 108 >>> p = Person(**dict(valid_params, birthdate=datetime.datetime(2000, 5, 3))) 102 >>> p.validate() 103 {} 109 >>> p.clean() 104 110 >>> p.birthdate 105 111 datetime.date(2000, 5, 3) 106 112 107 113 >>> p = Person(**dict(valid_params, birthdate='2000-05-03')) 108 >>> p.validate() 109 {} 114 >>> p.clean() 110 115 >>> p.birthdate 111 116 datetime.date(2000, 5, 3) 112 117 113 118 >>> p = Person(**dict(valid_params, birthdate='2000-5-3')) 114 >>> p.validate() 115 {} 119 >>> p.clean() 116 120 >>> p.birthdate 117 121 datetime.date(2000, 5, 3) 118 122 119 123 >>> p = Person(**dict(valid_params, birthdate='foo')) 120 >>> p.validate()['birthdate'] 121 [u'Enter a valid date in YYYY-MM-DD format.'] 124 >>> p.clean() 125 Traceback (most recent call last): 126 ... 127 ValidationError: {'birthdate': [u'Enter a valid date in YYYY-MM-DD format.']} 122 128 123 129 >>> p = Person(**dict(valid_params, favorite_moment=datetime.datetime(2002, 4, 3, 13, 23))) 124 >>> p.validate() 125 {} 130 >>> p.clean() 126 131 >>> p.favorite_moment 127 132 datetime.datetime(2002, 4, 3, 13, 23) 128 133 129 134 >>> p = Person(**dict(valid_params, favorite_moment=datetime.datetime(2002, 4, 3))) 130 >>> p.validate() 131 {} 135 >>> p.clean() 132 136 >>> p.favorite_moment 133 137 datetime.datetime(2002, 4, 3, 0, 0) 134 138 135 139 >>> p = Person(**dict(valid_params, best_time='16:20:00')) 136 >>> p.validate() 137 {} 140 >>> p.clean() 138 141 >>> p.best_time 139 142 datetime.time(16, 20) 140 143 141 144 >>> p = Person(**dict(valid_params, best_time='16:20')) 142 >>> p.validate() 143 {} 145 >>> p.clean() 144 146 >>> p.best_time 145 147 datetime.time(16, 20) 146 148 147 149 >>> p = Person(**dict(valid_params, best_time='bar')) 148 >>> p.validate()['best_time'] 149 [u'Enter a valid time in HH:MM[:ss[.uuuuuu]] format.'] 150 >>> p.clean()['best_time'] 151 Traceback (most recent call last): 152 ... 153 ValidationError: {'best_time': [u'Enter a valid time in HH:MM[:ss[.uuuuuu]] format.']} 150 154 151 155 >>> p = Person(**dict(valid_params, email='john@example.com')) 152 >>> p.validate() 153 {} 156 >>> p.clean() 154 157 >>> p.email 155 158 'john@example.com' 156 159 157 160 >>> p = Person(**dict(valid_params, email=u'john@example.com')) 158 >>> p.validate() 159 {} 161 >>> p.clean() 160 162 >>> p.email 161 163 u'john@example.com' 162 164 163 165 >>> p = Person(**dict(valid_params, email=22)) 164 >>> p.validate()['email'] 165 [u'Enter a valid e-mail address.'] 166 >>> p.clean() 167 Traceback (most recent call last): 168 ... 169 ValidationError: {'email': [u'Enter a valid e-mail address.']} 166 170 167 171 # Make sure that Date and DateTime return validation errors and don't raise Python errors. 168 >>> p = Person(name='John Doe', is_child=True, email='abc@def.com') 169 >>> errors = p.validate() 170 >>> errors['favorite_moment'] 171 [u'This field is required.'] 172 >>> errors['birthdate'] 172 >>> from django.core.exceptions import ValidationError 173 >>> try: 174 ... Person(name='John Doe', is_child=True, email='abc@def.com').clean() 175 ... except ValidationError, e: 176 ... e.message_dict['favorite_moment'] 177 ... e.message_dict['birthdate'] 173 178 [u'This field is required.'] 174 >>> errors['best_time']175 179 [u'This field is required.'] 176 180 177 181 """} -
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..469116c
- + 1 # -*- coding: UTF-8 -*- 2 tests = r""" 3 ################### 4 # ValidationError # 5 ################### 6 >>> from django.core.exceptions import ValidationError 7 >>> from django.utils.translation import ugettext_lazy 8 9 # Can take a string. 10 >>> print ValidationError("There was an error.").messages 11 <ul class="errorlist"><li>There was an error.</li></ul> 12 13 # Can take a unicode string. 14 >>> print ValidationError(u"Not \u03C0.").messages 15 <ul class="errorlist"><li>Not π.</li></ul> 16 17 # Can take a lazy string. 18 >>> print ValidationError(ugettext_lazy("Error.")).messages 19 <ul class="errorlist"><li>Error.</li></ul> 20 21 # Can take a list. 22 >>> print ValidationError(["Error one.", "Error two."]).messages 23 <ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul> 24 25 # Can take a mixture in a list. 26 >>> print ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages 27 <ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul> 28 29 >>> class VeryBadError: 30 ... def __unicode__(self): return u"A very bad error." 31 32 # Can take a non-string. 33 >>> print ValidationError(VeryBadError()).messages 34 <ul class="errorlist"><li>A very bad error.</li></ul> 35 """ 36 -
tests/regressiontests/forms/error_messages.py
diff --git a/tests/regressiontests/forms/error_messages.py b/tests/regressiontests/forms/error_messages.py index ec91b57..9b35551 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 a9aae4f..42be8bb 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. 3 is not one of the available choices 1012 1037 1013 1038 >>> f = ChoiceField(choices=[('1', 'One'), ('2', 'Two')], required=False) 1014 1039 >>> f.clean('') 1015 u''1016 1040 >>> f.clean(None) 1017 u''1018 1041 >>> f.clean(1) 1019 1042 u'1' 1020 1043 >>> f.clean('1') -
tests/regressiontests/forms/forms.py
diff --git a/tests/regressiontests/forms/forms.py b/tests/regressiontests/forms/forms.py index d834bda..0a9253f 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 68c082c..5272b2c 100644
a b u' id="header"' 18 18 u' class="news" title="Read this"' 19 19 >>> flatatt({}) 20 20 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 21 """