Django

Code

Ticket #6845: 6845-against-7625.diff

File 6845-against-7625.diff, 136.4 kB (added by Honza_Kral, 5 months ago)

new working patch

  • a/AUTHORS

    old new  
    387387    ymasuda@ethercube.com 
    388388    Jarek Zgoda <jarek.zgoda@gmail.com> 
    389389    Cheng Zhang 
     390    Honza Kral <Honza.Kral@gmail.com> 
    390391 
    391392A big THANK YOU goes to: 
    392393 
  • a/django/contrib/admin/views/template.py

    old new  
    11from django.contrib.admin.views.decorators import staff_member_required 
    2 from django.core import validators 
     2from django.core import validation 
    33from django import template, oldforms 
    44from django.template import loader 
    55from django.shortcuts import render_to_response 
     
    6969            error = e 
    7070        template.builtins.remove(register) 
    7171        if error: 
    72             raise validators.ValidationError, e.args 
     72            raise validation.ValidationError, e.args 
  • a/django/contrib/auth/forms.py

    old new  
    22from django.contrib.auth import authenticate 
    33from django.contrib.sites.models import Site 
    44from django.template import Context, loader 
    5 from django.core import validators 
     5from django.oldforms import validators 
    66from django import oldforms 
    77from django.utils.translation import ugettext as _ 
    88 
  • a/django/contrib/auth/management/commands/createsuperuser.py

    old new  
    3939            if not RE_VALID_USERNAME.match(username): 
    4040                raise CommandError("Invalid username. Use only letters, digits, and underscores") 
    4141            try: 
    42                 validators.isValidEmail(email, None
     42                validators.validate_email(email
    4343            except validators.ValidationError: 
    4444                raise CommandError("Invalid email address.") 
    4545 
  • a/django/contrib/auth/models.py

    old new  
    11from django.contrib import auth 
    2 from django.core import validators 
     2from django.oldforms import validators 
    33from django.core.exceptions import ImproperlyConfigured 
    44from django.db import models 
    55from django.db.models.manager import EmptyManager 
     
    135135 
    136136    Username and password are required. Other fields are optional. 
    137137    """ 
    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, validators=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores).")) 
    139139    first_name = models.CharField(_('first name'), max_length=30, blank=True) 
    140140    last_name = models.CharField(_('last name'), max_length=30, blank=True) 
    141141    email = models.EmailField(_('e-mail address'), blank=True) 
  • a/django/contrib/comments/views/comments.py

    old new  
    1 from django.core import validators 
     1from django.oldforms import validators 
    22from django import oldforms 
    33from django.core.mail import mail_admins, mail_managers 
    44from django.http import Http404 
  • a/django/contrib/flatpages/models.py

    old new  
    1 from django.core import validators 
     1from django.oldforms import validators 
    22from django.db import models 
    33from django.contrib.sites.models import Site 
    44from django.utils.translation import ugettext_lazy as _ 
    55 
    66 
    77class FlatPage(models.Model): 
    8     url = models.CharField(_('URL'), max_length=100, validator_list=[validators.isAlphaNumericURL], db_index=True, 
     8    url = models.CharField(_('URL'), max_length=100, validators=[validators.isAlphaNumericURL], db_index=True, 
    99        help_text=_("Example: '/about/contact/'. Make sure to have leading and trailing slashes.")) 
    1010    title = models.CharField(_('title'), max_length=200) 
    1111    content = models.TextField(_('content')) 
  • a/django/contrib/localflavor/br/forms.py

    old new  
    3131    } 
    3232 
    3333    def clean(self, value): 
    34         super(BRPhoneNumberField, self).clean(value) 
     34        value = super(BRPhoneNumberField, self).clean(value) 
    3535        if value in EMPTY_VALUES: 
    3636            return u'' 
    37         value = re.sub('(\(|\)|\s+)', '', smart_unicode(value)
     37        value = re.sub('(\(|\)|\s+)', '', value
    3838        m = phone_digits_re.search(value) 
    3939        if m: 
    4040            return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) 
  • a/django/contrib/localflavor/fi/forms.py

    old new  
    2929    } 
    3030 
    3131    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: 
    3437            return u'' 
    3538 
    3639        checkmarks = "0123456789ABCDEFHJKLMNPRSTUVWXY" 
  • a/django/contrib/localflavor/jp/forms.py

    old new  
    22JP-specific Form helpers 
    33""" 
    44 
    5 from django.core import validators 
    65from django.newforms import ValidationError 
    76from django.utils.translation import ugettext 
    87from django.newforms.fields import RegexField, Select 
  • /dev/null

    old new  
     1from django.utils.encoding import smart_unicode, StrAndUnicode, force_unicode 
     2from django.utils.safestring import mark_safe 
     3 
     4NON_FIELD_ERRORS = '__all__' 
     5 
     6class 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 
     25class 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 
     49class TypeCoercionError(ValidationError): 
     50    pass 
  • a/django/core/validators.py

    old new  
    11""" 
    22A library of validators that return None and raise ValidationError when the 
    33provided 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. 
    94""" 
    105 
    11 import urllib2 
    126import re 
    13 try: 
    14     from decimal import Decimal, DecimalException 
    15 except ImportError: 
    16     from django.utils._decimal import Decimal, DecimalException    # Python 2.3 
     7import urllib2 
    178 
    189from 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 
     10from django.utils.translation import ugettext as _ 
     11from django.core.validation import ValidationError 
     12 
     13def regexp_validator(regexp, message): 
     14    if isinstance(regexp, basestring): 
     15        regexp = re.compile(regexp) 
     16 
     17    def _regexp_validator(value): 
     18        if not regexp.search(value): 
     19            raise ValidationError, _(message) 
     20    return _regexp_validator 
    2221 
    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)) 
    3022email_re = re.compile( 
    3123    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom 
    3224    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string 
    3325    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+$') 
     26validate_email = regexp_validator(email_re, 'Enter a valid e-mail address.') 
    3927 
    40 lazy_inter = lazy(lambda a,b: force_unicode(a) % b, unicode) 
     28validate_ip_address4 = regexp_validator( 
     29        re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$'), 
     30        "Please enter a valid IP address." 
     31    ) 
    4132 
    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)] 
     33validate_phone_number = regexp_validator( 
     34        re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE), 
     35        _('Phone numbers must be in XXX-XXX-XXXX format.') 
     36    ) 
    5037 
    51     def __str__(self): 
    52         # This is needed because, without a __str__(), printing an exception 
    53         # instance would result in this: 
    54         # AttributeError: ValidationError instance has no attribute 'args' 
    55         # See http://www.python.org/doc/current/tut/node10.html#handling 
    56         return str(self.messages) 
     38validate_slug = regexp_validator( 
     39        re.compile(r'^[-\w]+$'), 
     40        "This value must contain only letters, numbers, underscores or hyphens." 
     41    ) 
    5742 
    58 class CriticalValidationError(Exception): 
    59     def __init__(self, message): 
    60         "ValidationError can be passed a string or a list." 
    61         if isinstance(message, list): 
    62             self.messages = [force_unicode(msg) for msg in message] 
    63         else: 
    64             assert isinstance(message, (basestring, Promise)), ("'%s' should be a string" % message) 
    65             self.messages = [force_unicode(message)] 
    66  
    67     def __str__(self): 
    68         return str(self.messages) 
    69  
    70 def isAlphaNumeric(field_data, all_data): 
    71     if not alnum_re.search(field_data): 
    72         raise ValidationError, _("This value must contain only letters, numbers and underscores.") 
    73  
    74 def isAlphaNumericURL(field_data, all_data): 
    75     if not alnumurl_re.search(field_data): 
    76         raise ValidationError, _("This value must contain only letters, numbers, underscores, dashes or slashes.") 
    77  
    78 def isSlug(field_data, all_data): 
    79     if not slug_re.search(field_data): 
    80         raise ValidationError, _("This value must contain only letters, numbers, underscores or hyphens.") 
    81  
    82 def isLowerCase(field_data, all_data): 
    83     if field_data.lower() != field_data: 
    84         raise ValidationError, _("Uppercase letters are not allowed here.") 
     43_datere = r'\d{4}-\d{1,2}-\d{1,2}' 
     44validate_ansi_date = regexp_validator( 
     45        re.compile('^%s$' % _datere), 
     46        _('Enter a valid date in YYYY-MM-DD format.') 
     47    ) 
    8548 
    86 def isUpperCase(field_data, all_data): 
    87     if field_data.upper() != field_data: 
    88         raise ValidationError, _("Lowercase letters are not allowed here.") 
     49_timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?' 
     50validate_ansi_time = regexp_validator( 
     51        re.compile('^%s$' % _timere), 
     52        _('Enter a valid time in HH:MM format.') 
     53    ) 
    8954 
    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.") 
     55validate_ansi_datetime = regexp_validator( 
     56        re.compile('^%s %s$' % (_datere, _timere)), 
     57        _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 
     58    ) 
    9659 
    97 def isCommaSeparatedEmailList(field_data, all_data): 
     60def validate_comma_separated_email_list(value): 
    9861    """ 
    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 whitespace 
     62    Checks that value is a string of e-mail addresses separated by commas. 
     63    Blank value values will not throw a validation error, and whitespace 
    10164    is allowed around the commas. 
    10265    """ 
    103     for supposed_email in field_data.split(','): 
     66    for supposed_email in value.split(','): 
    10467        try: 
    105             isValidEmail(supposed_email.strip(), ''
     68            validate_email(supposed_email.strip()
    10669        except ValidationError: 
    10770            raise ValidationError, _("Enter valid e-mail addresses separated by commas.") 
    10871 
    109 def isValidIPAddress4(field_data, all_data): 
    110     if not ip4_re.search(field_data): 
    111         raise ValidationError, _("Please enter a valid IP address.") 
    112  
    113 def isNotEmpty(field_data, all_data): 
    114     if field_data.strip() == '': 
    115         raise ValidationError, _("Empty values are not allowed here.") 
    116  
    117 def isOnlyDigits(field_data, all_data): 
    118     if not field_data.isdigit(): 
    119         raise ValidationError, _("Non-numeric characters aren't allowed here.") 
    120  
    121 def isNotOnlyDigits(field_data, all_data): 
    122     if field_data.isdigit(): 
    123         raise ValidationError, _("This value can't be comprised solely of digits.") 
    124  
    125 def isInteger(field_data, all_data): 
    126     # This differs from isOnlyDigits because this accepts the negative sign 
    127     if not integer_re.search(field_data): 
    128         raise ValidationError, _("Enter a whole number.") 
    129  
    130 def isOnlyLetters(field_data, all_data): 
    131     if not field_data.isalpha(): 
    132         raise ValidationError, _("Only alphabetical characters are allowed here.") 
    133  
    134 def _isValidDate(date_string): 
    135     """ 
    136     A helper function used by isValidANSIDate and isValidANSIDatetime to 
    137     check if the date is valid.  The date string is assumed to already be in 
    138     YYYY-MM-DD format. 
    139     """ 
    140     from datetime import date 
    141     # Could use time.strptime here and catch errors, but datetime.date below 
    142     # produces much friendlier error messages. 
    143     year, month, day = map(int, date_string.split('-')) 
    144     # This check is needed because strftime is used when saving the date 
    145     # value to the database, and strftime requires that the year be >=1900. 
    146     if year < 1900: 
    147         raise ValidationError, _('Year must be 1900 or later.') 
    148     try: 
    149         date(year, month, day) 
    150     except ValueError, e: 
    151         msg = _('Invalid date: %s') % _(str(e)) 
    152         raise ValidationError, msg 
    153  
    154 def isValidANSIDate(field_data, all_data): 
    155     if not ansi_date_re.search(field_data): 
    156         raise ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 
    157     _isValidDate(field_data) 
    158  
    159 def isValidANSITime(field_data, all_data): 
    160     if not ansi_time_re.search(field_data): 
    161         raise ValidationError, _('Enter a valid time in HH:MM format.') 
    162  
    163 def isValidANSIDatetime(field_data, all_data): 
    164     if not ansi_datetime_re.search(field_data): 
    165         raise ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') 
    166     _isValidDate(field_data.split()[0]) 
    167  
    168 def isValidEmail(field_data, all_data): 
    169     if not email_re.search(field_data): 
    170         raise ValidationError, _('Enter a valid e-mail address.') 
    171  
    172 def isValidImage(field_data, all_data): 
    173     """ 
    174     Checks that the file-upload field data contains a valid image (GIF, JPG, 
    175     PNG, possibly others -- whatever the Python Imaging Library supports). 
    176     """ 
    177     from PIL import Image 
    178     from cStringIO import StringIO 
    179     try: 
    180         content = field_data['content'] 
    181     except TypeError: 
    182         raise ValidationError, _("No file was submitted. Check the encoding type on the form.") 
    183     try: 
    184         # load() is the only method that can spot a truncated JPEG, 
    185         #  but it cannot be called sanely after verify() 
    186         trial_image = Image.open(StringIO(content)) 
    187         trial_image.load() 
    188         # verify() is the only method that can spot a corrupt PNG, 
    189         #  but it must be called immediately after the constructor 
    190         trial_image = Image.open(StringIO(content)) 
    191         trial_image.verify() 
    192     except Exception: # Python Imaging Library doesn't recognize it as an image 
    193         raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.") 
    194  
    195 def isValidImageURL(field_data, all_data): 
    196     uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png')) 
    197     try: 
    198         uc(field_data, all_data) 
    199     except URLMimeTypeCheck.InvalidContentType: 
    200         raise ValidationError, _("The URL %s does not point to a valid image.") % field_data 
    201  
    202 def isValidPhone(field_data, all_data): 
    203     if not phone_re.search(field_data): 
    204         raise ValidationError, _('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data 
    205  
    206 def isValidQuicktimeVideoURL(field_data, all_data): 
    207     "Checks that the given URL is a video that can be played by QuickTime (qt, mpeg)" 
    208     uc = URLMimeTypeCheck(('video/quicktime', 'video/mpeg',)) 
    209     try: 
    210         uc(field_data, all_data) 
    211     except URLMimeTypeCheck.InvalidContentType: 
    212         raise ValidationError, _("The URL %s does not point to a valid QuickTime video.") % field_data 
    213  
    214 def isValidURL(field_data, all_data): 
    215     if not url_re.search(field_data): 
    216         raise ValidationError, _("A valid URL is required.") 
    217  
    218 def isValidHTML(field_data, all_data): 
    219     import urllib, urllib2 
    220     try: 
    221         u = urllib2.urlopen('http://validator.w3.org/check', urllib.urlencode({'fragment': field_data, 'output': 'xml'})) 
    222     except: 
    223         # Validator or Internet connection is unavailable. Fail silently. 
    224         return 
    225     html_is_valid = (u.headers.get('x-w3c-validator-status', 'Invalid') == 'Valid') 
    226     if html_is_valid: 
    227         return 
    228     from xml.dom.minidom import parseString 
    229     error_messages = [e.firstChild.wholeText for e in parseString(u.read()).getElementsByTagName('messages')[0].getElementsByTagName('msg')] 
    230     raise ValidationError, _("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages) 
    231  
    232 def isWellFormedXml(field_data, all_data): 
    233     from xml.dom.minidom import parseString 
    234     try: 
    235         parseString(field_data) 
    236     except Exception, e: # Naked except because we're not sure what will be thrown 
    237         raise ValidationError, _("Badly formed XML: %s") % str(e) 
    238  
    239 def isWellFormedXmlFragment(field_data, all_data): 
    240     isWellFormedXml('<root>%s</root>' % field_data, all_data) 
    241  
    242 def isExistingURL(field_data, all_data): 
     72def validate_existing_url(value): 
    24373    try: 
    24474        headers = { 
    24575            "Accept" : "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", 
     
    24878            "Connection" : "close", 
    24979            "User-Agent": settings.URL_VALIDATOR_USER_AGENT 
    25080            } 
    251         req = urllib2.Request(field_data,None, headers) 
     81        req = urllib2.Request(value,None, headers) 
    25282        u = urllib2.urlopen(req) 
    25383    except ValueError: 
    254         raise ValidationError, _("Invalid URL: %s") % field_data 
     84        raise ValidationError, _("Invalid URL: %s") % value 
    25585    except urllib2.HTTPError, e: 
    25686        # 401s are valid; they just mean authorization is required. 
    25787        # 301 and 302 are redirects; they just mean look somewhere else. 
    25888        if str(e.code) not in ('401','301','302'): 
    259             raise ValidationError, _("The URL %s is a broken link.") % field_data 
     89            raise ValidationError, _("The URL %s is a broken link.") % value 
    26090    except: # urllib2.URLError, httplib.InvalidURL, etc. 
    261         raise ValidationError, _("The URL %s is a broken link.") % field_data 
    262  
    263 def isValidUSState(field_data, all_data): 
    264     "Checks that the given string is a valid two-letter U.S. state abbreviation" 
    265     states = ['AA', 'AE', 'AK', 'AL', 'AP', 'AR', 'AS', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'FM', 'GA', 'GU', 'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME', 'MH', 'MI', 'MN', 'MO', 'MP', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'PR', 'PW', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VA', 'VI', 'VT', 'WA', 'WI', 'WV', 'WY'] 
    266     if field_data.upper() not in states: 
    267         raise ValidationError, _("Enter a valid U.S. state abbreviation.") 
    268  
    269 def hasNoProfanities(field_data, all_data): 
    270     """ 
    271     Checks that the given string has no profanities in it. This does a simple 
    272     check for whether each profanity exists within the string, so 'fuck' will 
    273     catch 'motherfucker' as well. Raises a ValidationError such as: 
    274         Watch your mouth! The words "f--k" and "s--t" are not allowed here. 
    275     """ 
    276     field_data = field_data.lower() # normalize 
    277     words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data] 
    278     if words_seen: 
    279         from django.utils.text import get_text_list 
    280         plural = len(words_seen) 
    281         raise ValidationError, ungettext("Watch your mouth! The word %s is not allowed here.", 
    282             "Watch your mouth! The words %s are not allowed here.", plural) % \ 
    283             get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], _('and')) 
    284  
    285 class AlwaysMatchesOtherField(object): 
    286     def __init__(self, other_field_name, error_message=None): 
    287         self.other = other_field_name 
    288         self.error_message = error_message or lazy_inter(ugettext_lazy("This field must match the '%s' field."), self.other) 
    289         self.always_test = True 
    290  
    291     def __call__(self, field_data, all_data): 
    292         if field_data != all_data[self.other]: 
    293             raise ValidationError, self.error_message 
    294  
    295 class ValidateIfOtherFieldEquals(object): 
    296     def __init__(self, other_field, other_value, validator_list): 
    297         self.other_field, self.other_value = other_field, other_value 
    298         self.validator_list = validator_list 
    299         self.always_test = True 
    300  
    301     def __call__(self, field_data, all_data): 
    302         if self.other_field in all_data and all_data[self.other_field] == self.other_value: 
    303             for v in self.validator_list: 
    304                 v(field_data, all_data) 
    305  
    306 class RequiredIfOtherFieldNotGiven(object): 
    307     def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter something for at least one field.")): 
    308         self.other, self.error_message = other_field_name, error_message 
    309         self.always_test = True 
    310  
    311     def __call__(self, field_data, all_data): 
    312         if not all_data.get(self.other, False) and not field_data: 
    313             raise ValidationError, self.error_message 
    314  
    315 class RequiredIfOtherFieldsGiven(object): 
    316     def __init__(self, other_field_names, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")): 
    317         self.other, self.error_message = other_field_names, error_message 
    318         self.always_test = True 
    319  
    320     def __call__(self, field_data, all_data): 
    321         for field in self.other: 
    322             if all_data.get(field, False) and not field_data: 
    323                 raise ValidationError, self.error_message 
    324  
    325 class RequiredIfOtherFieldGiven(RequiredIfOtherFieldsGiven): 
    326     "Like RequiredIfOtherFieldsGiven, but takes a single field name instead of a list." 
    327     def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")): 
    328         RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message) 
    329  
    330 class RequiredIfOtherFieldEquals(object): 
    331     def __init__(self, other_field, other_value, error_message=None, other_label=None): 
    332         self.other_field = other_field 
    333         self.other_value = other_value 
    334         other_label = other_label or other_value 
    335         self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is %(value)s"), { 
    336             'field': other_field, 'value': other_label}) 
    337         self.always_test = True 
    338  
    339     def __call__(self, field_data, all_data): 
    340         if self.other_field in all_data and all_data[self.other_field] == self.other_value and not field_data: 
    341             raise ValidationError(self.error_message) 
    342  
    343 class RequiredIfOtherFieldDoesNotEqual(object): 
    344     def __init__(self, other_field, other_value, other_label=None, error_message=None): 
    345         self.other_field = other_field 
    346         self.other_value = other_value 
    347         other_label = other_label or other_value 
    348         self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is not %(value)s"), { 
    349             'field': other_field, 'value': other_label}) 
    350         self.always_test = True 
    351  
    352     def __call__(self, field_data, all_data): 
    353         if self.other_field in all_data and all_data[self.other_field] != self.other_value and not field_data: 
    354             raise ValidationError(self.error_message) 
    355  
    356 class IsLessThanOtherField(object): 
    357     def __init__(self, other_field_name, error_message): 
    358         self.other, self.error_message = other_field_name, error_message 
    359  
    360     def __call__(self, field_data, all_data): 
    361         if field_data > all_data[self.other]: 
    362             raise ValidationError, self.error_message 
    363  
    364 class UniqueAmongstFieldsWithPrefix(object): 
    365     def __init__(self, field_name, prefix, error_message): 
    366         self.field_name, self.prefix = field_name, prefix 
    367         self.error_message = error_message or ugettext_lazy("Duplicate values are not allowed.") 
    368  
    369     def __call__(self, field_data, all_data): 
    370         for field_name, value in all_data.items(): 
    371             if field_name != self.field_name and value == field_data: 
    372                 raise ValidationError, self.error_message 
    373  
    374 class NumberIsInRange(object): 
    375     """ 
    376     Validator that tests if a value is in a range (inclusive). 
    377     """ 
    378     def __init__(self, lower=None, upper=None, error_message=''): 
    379         self.lower, self.upper = lower, upper 
    380         if not error_message: 
    381             if lower and upper: 
    382                  self.error_message = _("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper} 
    383             elif lower: 
    384                 self.error_message = _("This value must be at least %s.") % lower 
    385             elif upper: 
    386                 self.error_message = _("This value must be no more than %s.") % upper 
    387         else: 
    388             self.error_message = error_message 
    389  
    390     def __call__(self, field_data, all_data): 
    391         # Try to make the value numeric. If this fails, we assume another 
    392         # validator will catch the problem. 
    393         try: 
    394             val = float(field_data) 
    395         except ValueError: 
    396             return 
    397  
    398         # Now validate 
    399         if self.lower and self.upper and (val < self.lower or val > self.upper): 
    400             raise ValidationError(self.error_message) 
    401         elif self.lower and val < self.lower: 
    402             raise ValidationError(self.error_message) 
    403         elif self.upper and val > self.upper: 
    404             raise ValidationError(self.error_message) 
    405  
    406 class IsAPowerOf(object): 
    407     """ 
    408     Usage: If you create an instance of the IsPowerOf validator: 
    409         v = IsAPowerOf(2) 
    410      
    411     The following calls will succeed: 
    412         v(4, None)  
    413         v(8, None) 
    414         v(16, None) 
    415      
    416     But this call: 
    417         v(17, None) 
    418     will raise "django.core.validators.ValidationError: ['This value must be a power of 2.']" 
    419     """ 
    420     def __init__(self, power_of): 
    421         self.power_of = power_of 
    422  
    423     def __call__(self, field_data, all_data): 
    424         from math import log 
    425         val = log(int(field_data)) / log(self.power_of) 
    426         if val != int(val): 
    427             raise ValidationError, _("This value must be a power of %s.") % self.power_of 
    428  
    429 class IsValidDecimal(object): 
    430     def __init__(self, max_digits, decimal_places): 
    431         self.max_digits, self.decimal_places = max_digits, decimal_places 
    432  
    433     def __call__(self, field_data, all_data): 
    434         try: 
    435             val = Decimal(field_data) 
    436         except DecimalException: 
    437             raise ValidationError, _("Please enter a valid decimal number.") 
    438  
    439         pieces = str(val).lstrip("-").split('.') 
    440         decimals = (len(pieces) == 2) and len(pieces[1]) or 0 
    441         digits = len(pieces[0]) 
    442  
    443         if digits + decimals > self.max_digits: 
    444             raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.", 
    445                 "Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits 
    446         if digits > (self.max_digits - self.decimal_places): 
    447             raise ValidationError, ungettext( "Please enter a valid decimal number with a whole part of at most %s digit.", 
    448                 "Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places) 
    449         if decimals > self.decimal_places: 
    450             raise ValidationError, ungettext("Please enter a valid decimal number with at most %s decimal place.", 
    451                 "Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places 
    452  
    453 def isValidFloat(field_data, all_data): 
    454     data = smart_str(field_data) 
    455     try: 
    456         float(data) 
    457     except ValueError: 
    458         raise ValidationError, _("Please enter a valid floating point number.") 
    459  
    460 class HasAllowableSize(object): 
    461     """ 
    462     Checks that the file-upload field data is a certain size. min_size and 
    463     max_size are measurements in bytes. 
    464     """ 
    465     def __init__(self, min_size=None, max_size=None, min_error_message=None, max_error_message=None): 
    466         self.min_size, self.max_size = min_size, max_size 
    467         self.min_error_message = min_error_message or lazy_inter(ugettext_lazy("Make sure your uploaded file is at least %s bytes big."), min_size) 
    468         self.max_error_message = max_error_message or lazy_inter(ugettext_lazy("Make sure your uploaded file is at most %s bytes big."), max_size) 
    469  
    470     def __call__(self, field_data, all_data): 
    471         try: 
    472             content = field_data['content'] 
    473         except TypeError: 
    474             raise ValidationError, ugettext_lazy("No file was submitted. Check the encoding type on the form.") 
    475         if self.min_size is not None and len(content) < self.min_size: 
    476             raise ValidationError, self.min_error_message 
    477         if self.max_size is not None and len(content) > self.max_size: 
    478             raise ValidationError, self.max_error_message 
    479  
    480 class MatchesRegularExpression(object): 
    481     """ 
    482     Checks that the field matches the given regular-expression. The regex 
    483     should be in string format, not already compiled. 
    484     """ 
    485     def __init__(self, regexp, error_message=ugettext_lazy("The format for this field is wrong.")): 
    486         self.regexp = re.compile(regexp) 
    487         self.error_message = error_message 
    488  
    489     def __call__(self, field_data, all_data): 
    490         if not self.regexp.search(field_data): 
    491             raise ValidationError(self.error_message) 
    492  
    493 class AnyValidator(object): 
    494     """ 
    495     This validator tries all given validators. If any one of them succeeds, 
    496     validation passes. If none of them succeeds, the given message is thrown 
    497     as a validation error. The message is rather unspecific, so it's best to 
    498     specify one on instantiation. 
    499     """ 
    500     def __init__(self, validator_list=None, error_message=ugettext_lazy("This field is invalid.")): 
    501         if validator_list is None: validator_list = [] 
    502         self.validator_list = validator_list 
    503         self.error_message = error_message 
    504         for v in validator_list: 
    505             if hasattr(v, 'always_test'): 
    506                 self.always_test = True 
    507  
    508     def __call__(self, field_data, all_data): 
    509         for v in self.validator_list: 
    510             try: 
    511                 v(field_data, all_data) 
    512                 return 
    513             except ValidationError, e: 
    514                 pass 
    515         raise ValidationError(self.error_message) 
     91        raise ValidationError, _("The URL %s is a broken link.") % value 
    51692 
    51793class URLMimeTypeCheck(object): 
    51894    "Checks that the provided URL points to a document with a listed mime type" 
     
    524100    def __init__(self, mime_type_list): 
    525101        self.mime_type_list = mime_type_list 
    526102 
    527     def __call__(self, field_data, all_data): 
    528         import urllib2 
     103    def __call__(self, value): 
     104        validate_existing_url(value) 
    529105        try: 
    530             isValidURL(field_data, all_data) 
    531         except ValidationError: 
    532             raise 
    533         try: 
    534             info = urllib2.urlopen(field_data).info() 
     106            info = urllib2.urlopen(value).info() 
    535107        except (urllib2.HTTPError, urllib2.URLError): 
    536             raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data 
     108            raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % value 
    537109        content_type = info['content-type'] 
    538110        if content_type not in self.mime_type_list: 
    539111            raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % { 
    540                 'url': field_data, 'contenttype': content_type} 
     112                'url': value, 'contenttype': content_type} 
    541113 
    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 
     114def validate_imaga_url(value): 
     115    uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png')) 
     116    try: 
     117        uc(value) 
     118    except URLMimeTypeCheck.InvalidContentType: 
     119        raise ValidationError, _("The URL %s does not point to a valid image.") % value 
    547120 
    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 
     121def validate_float(value): 
     122    data = smart_str(value) 
     123    try: 
     124        float(data) 
     125    except ValueError: 
     126        raise ValidationError, _("Please enter a valid floating point number.") 
  • a/django/db/models/__init__.py

    old new  
    11from django.conf import settings 
    22from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured 
    3 from django.core import validators 
    43from django.db import connection 
    54from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models 
    65from django.db.models.query import Q 
  • a/django/db/models/base.py

    old new  
    77import django.db.models.manipulators    # Imported to register signal handler. 
    88import django.db.models.manager         # Ditto. 
    99from django.core import validators 
     10from django.core.validation import ValidationError, NON_FIELD_ERRORS 
    1011from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError 
    1112from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist 
    1213from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField 
     
    1920from django.utils.datastructures import SortedDict 
    2021from django.utils.functional import curry 
    2122from django.utils.encoding import smart_str, force_unicode, smart_unicode 
     23from django.utils.translation import ugettext as _ 
    2224from django.conf import settings 
    2325 
    2426try: 
     
    346348 
    347349    save_base.alters_data = True 
    348350 
    349     def validate(self): 
     351    def clean(self, new_data=None): 
     352        self.to_python() 
     353        self.validate(new_data) 
     354 
     355    def to_python(self): 
     356        error_dict = {} 
     357        for f in self._meta.fields: 
     358            try: 
     359                value = f.to_python(getattr(self, f.attname, f.get_default())) 
     360                setattr(self, f.attname, value) 
     361            except ValidationError, e: 
     362                error_dict[f.name] = e.messages 
     363        if error_dict: 
     364            raise ValidationError(error_dict) 
     365 
     366    def validate(self, new_data=None): 
    350367        """ 
    351368        First coerces all fields on this instance to their proper Python types. 
    352369        Then runs validation on every field. Returns a dictionary of 
    353370        field_name -> error_list. 
    354371        """ 
     372        if new_data is not None: 
     373            def get_value(f): 
     374                if f.name in new_data: 
     375                    return f.to_python(new_data[f.name]) 
     376                return getattr(self, f.attname, f.get_default()) 
     377        else: 
     378            get_value = lambda f: getattr(self, f.attname, f.get_default()) 
    355379        error_dict = {} 
    356         invalid_python = {} 
    357380        for f in self._meta.fields: 
    358381            try: 
    359                 setattr(self, f.attname, f.to_python(getattr(self, f.attname, f.get_default()))) 
    360             except validators.ValidationError, e: 
     382                value = get_value(f) 
     383                f.validate(value, instance=self) 
     384                if hasattr(self, 'validate_%s' % f.name): 
     385                    getattr(self, 'validate_%s' % f.name)(value) 
     386            except ValidationError, e: 
    361387                error_dict[f.name] = e.messages 
    362                 invalid_python[f.name] = 1 
    363         for f in self._meta.fields: 
    364             if f.name in invalid_python: 
    365                 continue 
    366             errors = f.validate_full(getattr(self, f.attname, f.get_default()), self.__dict__) 
    367             if errors: 
    368                 error_dict[f.name] = errors 
    369         return error_dict 
     388 
     389        for un_together in self._meta.unique_together: 
     390            lookup = {} 
     391            for name in un_together: 
     392                if name in error_dict: 
     393                    break 
     394                f = self._meta.get_field(name) 
     395                lookup['%s__exact' % name] = get_value(f) 
     396            try: 
     397                qset = self.__class__._default_manager.all() 
     398                if self.pk: 
     399                    qset = qset.exclude(pk=self.pk) 
     400                obj = qset.get(**lookup) 
     401                error_dict[NON_FIELD_ERRORS] = _('Fields %s must be unique.') % ', '.join(un_together) 
     402            except self.DoesNotExist: 
     403                pass 
     404 
     405        if error_dict: 
     406            raise ValidationError(error_dict) 
    370407 
    371408    def _collect_sub_objects(self, seen_objs): 
    372409        """ 
  • a/django/db/models/fields/__init__.py

    old new  
    1212from django.db.models.query_utils import QueryWrapper 
    1313from django.dispatch import dispatcher 
    1414from django.conf import settings 
     15from django.oldforms import validators as oldvalidators 
    1516from django.core import validators 
    1617from django import oldforms 
    1718from django import newforms as forms 
     
    8384    creation_counter = 0 
    8485    auto_creation_counter = -1 
    8586 
     87    validators = [] 
     88 
    8689    def __init__(self, verbose_name=None, name=None, primary_key=False, 
    8790            max_length=None, unique=False, blank=False, null=False, 
    8891            db_index=False, core=False, rel=None, default=