Django

Code

Ticket #6845: 6845-against-django-7350.diff

File 6845-against-django-7350.diff, 134.9 kB (added by Honza_Kral, 7 months ago)
  • a/AUTHORS

    old new  
    379379    ymasuda@ethercube.com 
    380380    Jarek Zgoda <jarek.zgoda@gmail.com> 
    381381    Cheng Zhang 
     382    Honza Kral <Honza.Kral@gmail.com> 
    382383 
    383384A big THANK YOU goes to: 
    384385 
  • 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/create_superuser.py

    old new  
    6161            if not email: 
    6262                email = raw_input('E-mail address: ') 
    6363            try: 
    64                 validators.isValidEmail(email, None
     64                validators.validate_email(email
    6565            except validators.ValidationError: 
    6666                sys.stderr.write("Error: That e-mail address is invalid.\n") 
    6767                email = None 
  • 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/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 
     
    128128 
    129129    Username and password are required. Other fields are optional. 
    130130    """ 
    131     username = models.CharField(_('username'), max_length=30, unique=True, validator_list=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores).")) 
     131    username = models.CharField(_('username'), max_length=30, unique=True, validators=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores).")) 
    132132    first_name = models.CharField(_('first name'), max_length=30, blank=True) 
    133133    last_name = models.CharField(_('last name'), max_length=30, blank=True) 
    134134    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 
    66class FlatPage(models.Model): 
    7     url = models.CharField(_('URL'), max_length=100, validator_list=[validators.isAlphaNumericURL], db_index=True, 
     7    url = models.CharField(_('URL'), max_length=100, validators=[validators.isAlphaNumericURL], db_index=True, 
    88        help_text=_("Example: '/about/contact/'. Make sure to have leading and trailing slashes.")) 
    99    title = models.CharField(_('title'), max_length=200) 
    1010    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 
  • a/django/core/exceptions.py

    old new  
    2727class ImproperlyConfigured(Exception): 
    2828    "Django is somehow improperly configured" 
    2929    pass 
     30 
  • /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  
    88form field is required. 
    99""" 
    1010 
    11 import urllib2 
    1211import re 
    13 try: 
    14     from decimal import Decimal, DecimalException 
    15 except ImportError: 
    16     from django.utils._decimal import Decimal, DecimalException    # Python 2.3 
     12import urllib2 
    1713 
    1814from 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 
     15from django.utils.translation import ugettext as _ 
     16from django.core.validation import ValidationError 
     17 
     18def regexp_validator(regexp, message): 
     19    if isinstance(regexp, basestring): 
     20        regexp = re.compile(regexp) 
     21 
     22    def _regexp_validator(value): 
     23        if not regexp.search(value): 
     24            raise ValidationError, _(message) 
     25    return _regexp_validator 
    2226 
    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)) 
    3027email_re = re.compile( 
    3128    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom 
    3229    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string 
    3330    r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE)  # domain 
    34 integer_re = re.compile(r'^-?\d+$') 
    3531ip4_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}$') 
    3632phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE) 
    3733slug_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 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) 
    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.") 
    8534 
    86 def isUpperCase(field_data, all_data): 
    87     if field_data.upper() != field_data: 
    88         raise ValidationError, _("Lowercase letters are not allowed here.") 
    8935 
    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.") 
     36validate_email = regexp_validator(email_re, 'Enter a valid e-mail address.') 
     37validate_ip_address4 = regexp_validator(ip4_re, "Please enter a valid IP address.") 
     38validate_phone_number = regexp_validator(phone_re, _('Phone numbers must be in XXX-XXX-XXXX format.') ) 
     39validate_slug =regexp_validator(slug_re, "This value must contain only letters, numbers, underscores or hyphens.") 
    9640 
    97 def isCommaSeparatedEmailList(field_data, all_data): 
     41def isCommaSeparatedEmailList(value): 
    9842    """ 
    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 
     43    Checks that value is a string of e-mail addresses separated by commas. 
     44    Blank value values will not throw a validation error, and whitespace 
    10145    is allowed around the commas. 
    10246    """ 
    103     for supposed_email in field_data.split(','): 
     47    for supposed_email in value.split(','): 
    10448        try: 
    105             isValidEmail(supposed_email.strip(), ''
     49            validate_email(supposed_email.strip()
    10650        except ValidationError: 
    10751            raise ValidationError, _("Enter valid e-mail addresses separated by commas.") 
    10852 
    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): 
     53def validate_existing_url(value): 
    24354    try: 
    24455        headers = { 
    24556            "Accept" : "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", 
     
    24859            "Connection" : "close", 
    24960            "User-Agent": settings.URL_VALIDATOR_USER_AGENT 
    25061            } 
    251         req = urllib2.Request(field_data,None, headers) 
     62        req = urllib2.Request(value,None, headers) 
    25263        u = urllib2.urlopen(req) 
    25364    except ValueError: 
    254         raise ValidationError, _("Invalid URL: %s") % field_data 
     65        raise ValidationError, _("Invalid URL: %s") % value 
    25566    except urllib2.HTTPError, e: 
    25667        # 401s are valid; they just mean authorization is required. 
    25768        # 301 and 302 are redirects; they just mean look somewhere else. 
    25869        if str(e.code) not in ('401','301','302'): 
    259             raise ValidationError, _("The URL %s is a broken link.") % field_data 
     70            raise ValidationError, _("The URL %s is a broken link.") % value 
    26071    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) 
     72        raise ValidationError, _("The URL %s is a broken link.") % value 
    30573 
    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) 
    516  
    517 class URLMimeTypeCheck(object): 
    518     "Checks that the provided URL points to a document with a listed mime type" 
    519     class CouldNotRetrieve(ValidationError): 
    520         pass 
    521     class InvalidContentType(ValidationError): 
    522         pass 
    523  
    524     def __init__(self, mime_type_list): 
    525         self.mime_type_list = mime_type_list 
    526  
    527     def __call__(self, field_data, all_data): 
    528         import urllib2 
    529         try: 
    530             isValidURL(field_data, all_data) 
    531         except ValidationError: 
    532             raise 
    533         try: 
    534             info = urllib2.urlopen(field_data).info() 
    535         except (urllib2.HTTPError, urllib2.URLError): 
    536             raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data 
    537         content_type = info['content-type'] 
    538         if content_type not in self.mime_type_list: 
    539             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 
  • 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  
    11import django.db.models.manipulators 
    22import django.db.models.manager 
    3 from django.core import validators 
     3from django.core.validation import ValidationError, NON_FIELD_ERRORS 
    44from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned 
    55from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist 
    66from django.db.models.fields.related import OneToOneRel, ManyToOneRel 
     
    1313from django.utils.datastructures import SortedDict 
    1414from django.utils.functional import curry 
    1515from django.utils.encoding import smart_str, force_unicode, smart_unicode 
     16from django.utils.translation import ugettext as _ 
    1617from django.conf import settings 
    1718from itertools import izip 
    1819import types 
     
    277278 
    278279    save.alters_data = True 
    279280 
    280     def validate(self): 
     281    def clean(self, new_data=None): 
     282        self.to_python() 
     283        self.validate(new_data) 
     284 
     285    def to_python(self): 
     286        error_dict = {} 
     287        for f in self._meta.fields: 
     288            try: 
     289                value = f.to_python(getattr(self, f.attname, f.get_default())) 
     290                setattr(self, f.attname, value) 
     291            except ValidationError, e: 
     292                error_dict[f.name] = e.messages 
     293        if error_dict: 
     294            raise ValidationError(error_dict) 
     295 
     296    def validate(self, new_data=None): 
    281297        """ 
    282298        First coerces all fields on this instance to their proper Python types. 
    283299        Then runs validation on every field. Returns a dictionary of 
    284300        field_name -> error_list. 
    285301        """ 
     302        if new_data is not None: 
     303            def get_value(f): 
     304                if f.name in new_data: 
     305                    return f.to_python(new_data[f.name]) 
     306                return getattr(self, f.attname, f.get_default()) 
     307        else: 
     308            get_value = lambda f: getattr(self, f.attname, f.get_default()) 
    286309        error_dict = {} 
    287         invalid_python = {} 
    288310        for f in self._meta.fields: 
    289311            try: 
    290                 setattr(self, f.attname, f.to_python(getattr(self, f.attname, f.get_default()))) 
    291             except validators.ValidationError, e: 
     312                value = get_value(f) 
     313                f.validate(value, instance=self) 
     314                if hasattr(self, 'validate_%s' % f.name): 
     315                    getattr(self, 'validate_%s' % f.name)(value) 
     316            except ValidationError, e: 
    292317                error_dict[f.name] = e.messages 
    293                 invalid_python[f.name] = 1 
    294         for f in self._meta.fields: 
    295             if f.name in invalid_python: 
    296                 continue 
    297             errors = f.validate_full(getattr(self, f.attname, f.get_default()), self.__dict__) 
    298             if errors: 
    299                 error_dict[f.name] = errors 
    300         return error_dict 
     318 
     319        for un_together in self._meta.unique_together: 
     320            lookup = {} 
     321            for name in un_together: 
     322                if name in error_dict: 
     323                    break 
     324                f = self._meta.get_field(name) 
     325                lookup['%s__exact' % name] = get_value(f) 
     326            try: 
     327                qset = self.__class__._default_manager.all() 
     328                if self.pk: 
     329                    qset = qset.exclude(pk=self.pk) 
     330                obj = qset.get(**lookup) 
     331                error_dict[NON_FIELD_ERRORS] = _('Fields %s must be unique.') % ', '.join(un_together) 
     332            except self.DoesNotExist: 
     333                pass 
     334 
     335        if error_dict: 
     336            raise ValidationError(error_dict) 
    301337 
    302338    def _collect_sub_objects(self, seen_objs): 
    303339        """ 
  • a/django/db/models/fields/__init__.py

    old new  
    1010from django.db.models import signals 
    1111from django.dispatch import dispatcher 
    1212from django.conf import settings 
     13from django.oldforms import validators as oldvalidators 
    1314from django.core import validators 
    1415from django import oldforms 
    1516from django import newforms as forms 
     
    7879    # Tracks each time a Field instance is created. Used to retain order. 
    7980    creation_counter = 0 
    8081 
     82    validators = [] 
     83 
    8184    def __init__(self, verbose_name=None, name=None, primary_key=False, 
    8285        max_length=None, unique=False, blank=False, null=False, db_index=False, 
    8386        core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True, 
    8487        prepopulate_from=None, unique_for_date=None, unique_for_month=None, 
    8588        unique_for_year=None, validator_list=None, choices=None, radio_admin=None, 
    86         help_text='', db_column=None, db_tablespace=None): 
     89        help_text='', db_column=None, db_tablespace=None, validators=[]): 
    8790        self.name = name 
    8891        self.verbose_name = verbose_name 
    8992        self.primary_key = primary_key 
     
    9699  &