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