Fixed #5871 -- Factored out the validation errors in localflavor form fields. Brings them into line with the standard newforms fields. Patch from Jan Rademaker.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6926 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2007-12-17 08:05:27 +00:00
parent 4d7aa81a70
commit 1fcb4e4bcd
23 changed files with 375 additions and 217 deletions

View File

@ -24,18 +24,20 @@ class ARPostalCodeField(RegexField):
See http://www.correoargentino.com.ar/consulta_cpa/home.php See http://www.correoargentino.com.ar/consulta_cpa/home.php
""" """
default_error_messages = {
'invalid': ugettext("Enter a postal code in the format NNNN or ANNNNAAA."),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ARPostalCodeField, self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$', super(ARPostalCodeField, self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$',
min_length=4, max_length=8, min_length=4, max_length=8, *args, **kwargs)
error_message=ugettext("Enter a postal code in the format NNNN or ANNNNAAA."),
*args, **kwargs)
def clean(self, value): def clean(self, value):
value = super(ARPostalCodeField, self).clean(value) value = super(ARPostalCodeField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
if len(value) not in (4, 8): if len(value) not in (4, 8):
raise ValidationError(ugettext("Enter a postal code in the format NNNN or ANNNNAAA.")) raise ValidationError(self.error_messages['invalid'])
if len(value) == 8: if len(value) == 8:
return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper()) return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper())
return value return value
@ -44,6 +46,11 @@ class ARDNIField(CharField):
""" """
A field that validates `Documento Nacional de Identidad´ (DNI) numbers. A field that validates `Documento Nacional de Identidad´ (DNI) numbers.
""" """
default_error_messages = {
'invalid': ugettext("This field requires only numbers."),
'max_digits': ugettext("This field requires 7 or 8 digits."),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ARDNIField, self).__init__(max_length=10, min_length=7, *args, super(ARDNIField, self).__init__(max_length=10, min_length=7, *args,
**kwargs) **kwargs)
@ -58,10 +65,9 @@ class ARDNIField(CharField):
if not value.isdigit(): if not value.isdigit():
value = value.replace('.', '') value = value.replace('.', '')
if not value.isdigit(): if not value.isdigit():
raise ValidationError(ugettext("This field requires only numbers.")) raise ValidationError(self.error_messages['invalid'])
if len(value) not in (7, 8): if len(value) not in (7, 8):
raise ValidationError( raise ValidationError(self.error_messages['max_digits'])
ugettext("This field requires 7 or 8 digits."))
return value return value
@ -70,9 +76,13 @@ class ARCUITField(RegexField):
This field validates a CUIT (Código Único de Identificación Tributaria). A This field validates a CUIT (Código Único de Identificación Tributaria). A
CUIT is of the form XX-XXXXXXXX-V. The last digit is a check digit. CUIT is of the form XX-XXXXXXXX-V. The last digit is a check digit.
""" """
default_error_messages = {
'invalid': ugettext('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),
'checksum': ugettext("Invalid CUIT."),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ARCUITField, self).__init__(r'^\d{2}-?\d{8}-?\d$', super(ARCUITField, self).__init__(r'^\d{2}-?\d{8}-?\d$',
error_message=ugettext('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),
*args, **kwargs) *args, **kwargs)
def clean(self, value): def clean(self, value):
@ -85,7 +95,7 @@ class ARCUITField(RegexField):
return u'' return u''
value, cd = self._canon(value) value, cd = self._canon(value)
if self._calc_cd(value) != cd: if self._calc_cd(value) != cd:
raise ValidationError(ugettext("Invalid CUIT.")) raise ValidationError(self.error_messages['checksum'])
return self._format(value, cd) return self._format(value, cd)
def _canon(self, cuit): def _canon(self, cuit):

View File

@ -12,14 +12,20 @@ PHONE_DIGITS_RE = re.compile(r'^(\d{10})$')
class AUPostCodeField(RegexField): class AUPostCodeField(RegexField):
"""Australian post code field.""" """Australian post code field."""
default_error_messages = {
'invalid': ugettext('Enter a 4 digit post code.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(AUPostCodeField, self).__init__(r'^\d{4}$', super(AUPostCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext('Enter a 4 digit post code.'),
*args, **kwargs)
class AUPhoneNumberField(Field): class AUPhoneNumberField(Field):
"""Australian phone number field.""" """Australian phone number field."""
default_error_messages = {
'invalid': u'Phone numbers must contain 10 digits.',
}
def clean(self, value): def clean(self, value):
""" """
Validate a phone number. Strips parentheses, whitespace and hyphens. Validate a phone number. Strips parentheses, whitespace and hyphens.
@ -31,7 +37,7 @@ class AUPhoneNumberField(Field):
phone_match = PHONE_DIGITS_RE.search(value) phone_match = PHONE_DIGITS_RE.search(value)
if phone_match: if phone_match:
return u'%s' % phone_match.group(1) return u'%s' % phone_match.group(1)
raise ValidationError(u'Phone numbers must contain 10 digits.') raise ValidationError(self.error_messages['invalid'])
class AUStateSelect(Select): class AUStateSelect(Select):
""" """

View File

@ -17,13 +17,19 @@ except NameError:
phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$') phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$')
class BRZipCodeField(RegexField): class BRZipCodeField(RegexField):
default_error_messages = {
'invalid': _('Enter a zip code in the format XXXXX-XXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$', super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=_('Enter a zip code in the format XXXXX-XXX.'),
*args, **kwargs)
class BRPhoneNumberField(Field): class BRPhoneNumberField(Field):
default_error_messages = {
'invalid': _('Phone numbers must be in XX-XXXX-XXXX format.'),
}
def clean(self, value): def clean(self, value):
super(BRPhoneNumberField, self).clean(value) super(BRPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
@ -32,7 +38,7 @@ class BRPhoneNumberField(Field):
m = phone_digits_re.search(value) m = phone_digits_re.search(value)
if m: if m:
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
raise ValidationError(_('Phone numbers must be in XX-XXXX-XXXX format.')) raise ValidationError(self.error_messages['invalid'])
class BRStateSelect(Select): class BRStateSelect(Select):
""" """
@ -48,6 +54,9 @@ class BRStateChoiceField(Field):
A choice field that uses a list of Brazilian states as its choices. A choice field that uses a list of Brazilian states as its choices.
""" """
widget = Select widget = Select
default_error_messages = {
'invalid': _(u'Select a valid brazilian state. That state is not one of the available states.'),
}
def __init__(self, required=True, widget=None, label=None, def __init__(self, required=True, widget=None, label=None,
initial=None, help_text=None): initial=None, help_text=None):
@ -65,9 +74,7 @@ class BRStateChoiceField(Field):
return value return value
valid_values = set([smart_unicode(k) for k, v in self.widget.choices]) valid_values = set([smart_unicode(k) for k, v in self.widget.choices])
if value not in valid_values: if value not in valid_values:
raise ValidationError(_(u'Select a valid brazilian state.' raise ValidationError(self.error_messages['invalid'])
u' That state is not one'
u' of the available states.'))
return value return value
def DV_maker(v): def DV_maker(v):
@ -83,6 +90,12 @@ class BRCPFField(CharField):
More information: More information:
http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas
""" """
default_error_messages = {
'invalid': _("Invalid CPF number."),
'max_digits': _("This field requires at most 11 digits or 14 characters."),
'digits_only': _("This field requires only numbers."),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(BRCPFField, self).__init__(max_length=14, min_length=11, *args, **kwargs) super(BRCPFField, self).__init__(max_length=14, min_length=11, *args, **kwargs)
@ -100,9 +113,9 @@ class BRCPFField(CharField):
try: try:
int(value) int(value)
except ValueError: except ValueError:
raise ValidationError(_("This field requires only numbers.")) raise ValidationError(self.error_messages['digits_only'])
if len(value) != 11: if len(value) != 11:
raise ValidationError(_("This field requires at most 11 digits or 14 characters.")) raise ValidationError(self.error_messages['max_digits'])
orig_dv = value[-2:] orig_dv = value[-2:]
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))]) new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))])
@ -112,11 +125,17 @@ class BRCPFField(CharField):
new_2dv = DV_maker(new_2dv % 11) new_2dv = DV_maker(new_2dv % 11)
value = value[:-1] + str(new_2dv) value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv: if value[-2:] != orig_dv:
raise ValidationError(_("Invalid CPF number.")) raise ValidationError(self.error_messages['invalid'])
return orig_value return orig_value
class BRCNPJField(Field): class BRCNPJField(Field):
default_error_messages = {
'invalid': _("Invalid CNPJ number."),
'digits_only': _("This field requires only numbers."),
'max_digits': _("This field requires at least 14 digits"),
}
def clean(self, value): def clean(self, value):
""" """
Value can be either a string in the format XX.XXX.XXX/XXXX-XX or a Value can be either a string in the format XX.XXX.XXX/XXXX-XX or a
@ -131,10 +150,9 @@ class BRCNPJField(Field):
try: try:
int(value) int(value)
except ValueError: except ValueError:
raise ValidationError("This field requires only numbers.") raise ValidationError(self.error_messages['digits_only'])
if len(value) != 14: if len(value) != 14:
raise ValidationError( raise ValidationError(self.error_messages['max_digits'])
_("This field requires at least 14 digits"))
orig_dv = value[-2:] orig_dv = value[-2:]
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))]) new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))])
@ -144,7 +162,6 @@ class BRCNPJField(Field):
new_2dv = DV_maker(new_2dv % 11) new_2dv = DV_maker(new_2dv % 11)
value = value[:-1] + str(new_2dv) value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv: if value[-2:] != orig_dv:
raise ValidationError(_("Invalid CNPJ number.")) raise ValidationError(self.error_messages['invalid'])
return orig_value return orig_value

View File

@ -13,14 +13,20 @@ sin_re = re.compile(r"^(\d{3})-(\d{3})-(\d{3})$")
class CAPostalCodeField(RegexField): class CAPostalCodeField(RegexField):
"""Canadian postal code field.""" """Canadian postal code field."""
default_error_messages = {
'invalid': gettext(u'Enter a postal code in the format XXX XXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$', super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=gettext(u'Enter a postal code in the format XXX XXX.'),
*args, **kwargs)
class CAPhoneNumberField(Field): class CAPhoneNumberField(Field):
"""Canadian phone number field.""" """Canadian phone number field."""
default_error_messages = {
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
}
def clean(self, value): def clean(self, value):
"""Validate a phone number. """Validate a phone number.
""" """
@ -31,7 +37,7 @@ class CAPhoneNumberField(Field):
m = phone_digits_re.search(value) m = phone_digits_re.search(value)
if m: if m:
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.') raise ValidationError(self.error_messages['invalid'])
class CAProvinceField(Field): class CAProvinceField(Field):
""" """
@ -39,6 +45,10 @@ class CAProvinceField(Field):
It normalizes the input to the standard two-leter postal service It normalizes the input to the standard two-leter postal service
abbreviation for the given province. abbreviation for the given province.
""" """
default_error_messages = {
'invalid': u'Enter a Canadian province or territory.',
}
def clean(self, value): def clean(self, value):
from ca_provinces import PROVINCES_NORMALIZED from ca_provinces import PROVINCES_NORMALIZED
super(CAProvinceField, self).clean(value) super(CAProvinceField, self).clean(value)
@ -53,7 +63,7 @@ class CAProvinceField(Field):
return PROVINCES_NORMALIZED[value.strip().lower()].decode('ascii') return PROVINCES_NORMALIZED[value.strip().lower()].decode('ascii')
except KeyError: except KeyError:
pass pass
raise ValidationError(u'Enter a Canadian province or territory.') raise ValidationError(self.error_messages['invalid'])
class CAProvinceSelect(Select): class CAProvinceSelect(Select):
""" """
@ -74,19 +84,23 @@ class CASocialInsuranceNumberField(Field):
* Passes the check digit process "Luhn Algorithm" * Passes the check digit process "Luhn Algorithm"
See: http://en.wikipedia.org/wiki/Social_Insurance_Number See: http://en.wikipedia.org/wiki/Social_Insurance_Number
""" """
default_error_messages = {
'invalid': ugettext('Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.'),
}
def clean(self, value): def clean(self, value):
super(CASocialInsuranceNumberField, self).clean(value) super(CASocialInsuranceNumberField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
msg = ugettext('Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.')
match = re.match(sin_re, value) match = re.match(sin_re, value)
if not match: if not match:
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
number = u'%s-%s-%s' % (match.group(1), match.group(2), match.group(3)) number = u'%s-%s-%s' % (match.group(1), match.group(2), match.group(3))
check_number = u'%s%s%s' % (match.group(1), match.group(2), match.group(3)) check_number = u'%s%s%s' % (match.group(1), match.group(2), match.group(3))
if not self.luhn_checksum_is_valid(check_number): if not self.luhn_checksum_is_valid(check_number):
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
return number return number
def luhn_checksum_is_valid(self, number): def luhn_checksum_is_valid(self, number):

View File

@ -12,11 +12,13 @@ id_re = re.compile(r"^(?P<idnumber>\w{8})(?P<pos9>(\d{1}|<))(?P<checksum>\d{1})$
phone_digits_re = re.compile(r'^0([1-9]{1})\d{8}$') phone_digits_re = re.compile(r'^0([1-9]{1})\d{8}$')
class CHZipCodeField(RegexField): class CHZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(CHZipCodeField, self).__init__(r'^\d{4}$', super(CHZipCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext('Enter a zip code in the format XXXX.'),
*args, **kwargs)
class CHPhoneNumberField(Field): class CHPhoneNumberField(Field):
""" """
@ -25,6 +27,10 @@ class CHPhoneNumberField(Field):
'0XX.XXX.XX.XX' and '0XXXXXXXXX' validate but are corrected to '0XX.XXX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
'0XX XXX XX XX'. '0XX XXX XX XX'.
""" """
default_error_messages = {
'invalid': 'Phone numbers must be in 0XX XXX XX XX format.',
}
def clean(self, value): def clean(self, value):
super(CHPhoneNumberField, self).clean(value) super(CHPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
@ -33,7 +39,7 @@ class CHPhoneNumberField(Field):
m = phone_digits_re.search(value) m = phone_digits_re.search(value)
if m: if m:
return u'%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10]) return u'%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
raise ValidationError('Phone numbers must be in 0XX XXX XX XX format.') raise ValidationError(self.error_messages['invalid'])
class CHStateSelect(Select): class CHStateSelect(Select):
""" """
@ -54,6 +60,10 @@ class CHIdentityCardNumberField(Field):
Algorithm is documented at http://adi.kousz.ch/artikel/IDCHE.htm Algorithm is documented at http://adi.kousz.ch/artikel/IDCHE.htm
""" """
default_error_messages = {
'invalid': ugettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.'),
}
def has_valid_checksum(self, number): def has_valid_checksum(self, number):
given_number, given_checksum = number[:-1], number[-1] given_number, given_checksum = number[:-1], number[-1]
new_number = given_number new_number = given_number
@ -87,23 +97,22 @@ class CHIdentityCardNumberField(Field):
def clean(self, value): def clean(self, value):
super(CHIdentityCardNumberField, self).clean(value) super(CHIdentityCardNumberField, self).clean(value)
error_msg = ugettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.')
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
match = re.match(id_re, value) match = re.match(id_re, value)
if not match: if not match:
raise ValidationError(error_msg) raise ValidationError(self.error_messages['invalid'])
idnumber, pos9, checksum = match.groupdict()['idnumber'], match.groupdict()['pos9'], match.groupdict()['checksum'] idnumber, pos9, checksum = match.groupdict()['idnumber'], match.groupdict()['pos9'], match.groupdict()['checksum']
if idnumber == '00000000' or \ if idnumber == '00000000' or \
idnumber == 'A0000000': idnumber == 'A0000000':
raise ValidationError(error_msg) raise ValidationError(self.error_messages['invalid'])
all_digits = "%s%s%s" % (idnumber, pos9, checksum) all_digits = "%s%s%s" % (idnumber, pos9, checksum)
if not self.has_valid_checksum(all_digits): if not self.has_valid_checksum(all_digits):
raise ValidationError(error_msg) raise ValidationError(self.error_messages['invalid'])
return u'%s%s%s' % (idnumber, pos9, checksum) return u'%s%s%s' % (idnumber, pos9, checksum)

View File

@ -25,16 +25,21 @@ class CLRutField(RegexField):
Samples for testing are available from Samples for testing are available from
https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html
""" """
default_error_messages = {
'invalid': ugettext('Enter a valid Chilean RUT.'),
'strict': ugettext('Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.'),
'checksum': ugettext('The Chilean RUT is not valid.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if 'strict' in kwargs: if 'strict' in kwargs:
del kwargs['strict'] del kwargs['strict']
super(CLRutField, self).__init__(r'^(\d{1,2}\.)?\d{3}\.\d{3}-[\dkK]$', super(CLRutField, self).__init__(r'^(\d{1,2}\.)?\d{3}\.\d{3}-[\dkK]$',
error_message=ugettext('Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'), error_message=self.default_error_messages['strict'], *args, **kwargs)
*args, **kwargs)
else: else:
# In non-strict mode, accept RUTs that validate but do not exist in # In non-strict mode, accept RUTs that validate but do not exist in
# the real world. # the real world.
super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', error_message=ugettext('Enter valid a Chilean RUT'), *args, **kwargs) super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', *args, **kwargs)
def clean(self, value): def clean(self, value):
""" """
@ -47,7 +52,7 @@ class CLRutField(RegexField):
if self._algorithm(rut) == verificador: if self._algorithm(rut) == verificador:
return self._format(rut, verificador) return self._format(rut, verificador)
else: else:
raise ValidationError(u'The Chilean RUT is not valid.') raise ValidationError(self.error_messages['checksum'])
def _algorithm(self, rut): def _algorithm(self, rut):
""" """

View File

@ -10,11 +10,12 @@ import re
id_re = re.compile(r"^(?P<residence>\d{10})(?P<origin>\w{1,3})[-\ ]?(?P<birthday>\d{7})[-\ ]?(?P<validity>\d{7})[-\ ]?(?P<checksum>\d{1})$") id_re = re.compile(r"^(?P<residence>\d{10})(?P<origin>\w{1,3})[-\ ]?(?P<birthday>\d{7})[-\ ]?(?P<validity>\d{7})[-\ ]?(?P<checksum>\d{1})$")
class DEZipCodeField(RegexField): class DEZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(DEZipCodeField, self).__init__(r'^\d{5}$', super(DEZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext('Enter a zip code in the format XXXXX.'),
*args, **kwargs)
class DEStateSelect(Select): class DEStateSelect(Select):
""" """
@ -36,6 +37,10 @@ class DEIdentityCardNumberField(Field):
Algorithm is documented at http://de.wikipedia.org/wiki/Personalausweis Algorithm is documented at http://de.wikipedia.org/wiki/Personalausweis
""" """
default_error_messages = {
'invalid': ugettext('Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.'),
}
def has_valid_checksum(self, number): def has_valid_checksum(self, number):
given_number, given_checksum = number[:-1], number[-1] given_number, given_checksum = number[:-1], number[-1]
calculated_checksum = 0 calculated_checksum = 0
@ -57,23 +62,22 @@ class DEIdentityCardNumberField(Field):
def clean(self, value): def clean(self, value):
super(DEIdentityCardNumberField, self).clean(value) super(DEIdentityCardNumberField, self).clean(value)
error_msg = ugettext('Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.')
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
match = re.match(id_re, value) match = re.match(id_re, value)
if not match: if not match:
raise ValidationError(error_msg) raise ValidationError(self.error_messages['invalid'])
gd = match.groupdict() gd = match.groupdict()
residence, origin = gd['residence'], gd['origin'] residence, origin = gd['residence'], gd['origin']
birthday, validity, checksum = gd['birthday'], gd['validity'], gd['checksum'] birthday, validity, checksum = gd['birthday'], gd['validity'], gd['checksum']
if residence == '0000000000' or birthday == '0000000' or validity == '0000000': if residence == '0000000000' or birthday == '0000000' or validity == '0000000':
raise ValidationError(error_msg) raise ValidationError(self.error_messages['invalid'])
all_digits = u"%s%s%s%s" % (residence, birthday, validity, checksum) all_digits = u"%s%s%s%s" % (residence, birthday, validity, checksum)
if not self.has_valid_checksum(residence) or not self.has_valid_checksum(birthday) or \ if not self.has_valid_checksum(residence) or not self.has_valid_checksum(birthday) or \
not self.has_valid_checksum(validity) or not self.has_valid_checksum(all_digits): not self.has_valid_checksum(validity) or not self.has_valid_checksum(all_digits):
raise ValidationError(error_msg) raise ValidationError(self.error_messages['invalid'])
return u'%s%s-%s-%s-%s' % (residence, origin, birthday, validity, checksum) return u'%s%s-%s-%s-%s' % (residence, origin, birthday, validity, checksum)

View File

@ -15,12 +15,14 @@ class ESPostalCodeField(RegexField):
Spanish postal code is a five digits string, with two first digits Spanish postal code is a five digits string, with two first digits
between 01 and 52, assigned to provinces code. between 01 and 52, assigned to provinces code.
""" """
default_error_messages = {
'invalid': _('Enter a valid postal code in the range and format 01XXX - 52XXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ESPostalCodeField, self).__init__( super(ESPostalCodeField, self).__init__(
r'^(0[1-9]|[1-4][0-9]|5[0-2])\d{3}$', r'^(0[1-9]|[1-4][0-9]|5[0-2])\d{3}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=_('Enter a valid postal code in the range and format 01XXX - 52XXX.'),
*args, **kwargs)
class ESPhoneNumberField(RegexField): class ESPhoneNumberField(RegexField):
""" """
@ -33,11 +35,13 @@ class ESPhoneNumberField(RegexField):
TODO: accept and strip characters like dot, hyphen... in phone number TODO: accept and strip characters like dot, hyphen... in phone number
""" """
default_error_messages = {
'invalid': _('Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ESPhoneNumberField, self).__init__(r'^(6|8|9)\d{8}$', super(ESPhoneNumberField, self).__init__(r'^(6|8|9)\d{8}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=_('Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.'),
*args, **kwargs)
class ESIdentityCardNumberField(RegexField): class ESIdentityCardNumberField(RegexField):
""" """
@ -58,19 +62,23 @@ class ESIdentityCardNumberField(RegexField):
public, and different authors have different opinions on which ones allows public, and different authors have different opinions on which ones allows
letters, so both validations are assumed true for all types. letters, so both validations are assumed true for all types.
""" """
default_error_messages = {
'invalid': _('Please enter a valid NIF, NIE, or CIF.'),
'invalid_only_nif': _('Please enter a valid NIF or NIE.'),
'invalid_nif': _('Invalid checksum for NIF.'),
'invalid_nie': _('Invalid checksum for NIE.'),
'invalid_cif': _('Invalid checksum for CIF.'),
}
def __init__(self, only_nif=False, *args, **kwargs): def __init__(self, only_nif=False, *args, **kwargs):
self.only_nif = only_nif self.only_nif = only_nif
self.nif_control = 'TRWAGMYFPDXBNJZSQVHLCKE' self.nif_control = 'TRWAGMYFPDXBNJZSQVHLCKE'
self.cif_control = 'JABCDEFGHI' self.cif_control = 'JABCDEFGHI'
self.cif_types = 'ABCDEFGHKLMNPQS' self.cif_types = 'ABCDEFGHKLMNPQS'
self.nie_types = 'XT' self.nie_types = 'XT'
if self.only_nif:
self.id_types = 'NIF or NIE'
else:
self.id_types = 'NIF, NIE, or CIF'
super(ESIdentityCardNumberField, self).__init__(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types + self.cif_types.lower() + self.nie_types.lower(), self.nif_control + self.nif_control.lower()), super(ESIdentityCardNumberField, self).__init__(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types + self.cif_types.lower() + self.nie_types.lower(), self.nif_control + self.nif_control.lower()),
max_length=None, min_length=None, max_length=None, min_length=None,
error_message=_('Please enter a valid %s.' % self.id_types), error_message=self.default_error_messages['invalid%s' % (self.only_nif and '_only_nif' or '')],
*args, **kwargs) *args, **kwargs)
def clean(self, value): def clean(self, value):
@ -88,13 +96,13 @@ class ESIdentityCardNumberField(RegexField):
if letter2 == nif_get_checksum(number): if letter2 == nif_get_checksum(number):
return value return value
else: else:
raise ValidationError, _('Invalid checksum for NIF.') raise ValidationError, self.error_messages['invalid_nif']
elif letter1 in self.nie_types and letter2: elif letter1 in self.nie_types and letter2:
# NIE # NIE
if letter2 == nif_get_checksum(number): if letter2 == nif_get_checksum(number):
return value return value
else: else:
raise ValidationError, _('Invalid checksum for NIE.') raise ValidationError, self.error_messages['invalid_nie']
elif not self.only_nif and letter1 in self.cif_types and len(number) in [7, 8]: elif not self.only_nif and letter1 in self.cif_types and len(number) in [7, 8]:
# CIF # CIF
if not letter2: if not letter2:
@ -103,9 +111,9 @@ class ESIdentityCardNumberField(RegexField):
if letter2 in [checksum, self.cif_control[checksum]]: if letter2 in [checksum, self.cif_control[checksum]]:
return value return value
else: else:
raise ValidationError, _('Invalid checksum for CIF.') raise ValidationError, self.error_messages['invalid_cif']
else: else:
raise ValidationError, _('Please enter a valid %s.' % self.id_types) raise ValidationError, self.error_messages['invalid']
class ESCCCField(RegexField): class ESCCCField(RegexField):
""" """
@ -130,11 +138,14 @@ class ESCCCField(RegexField):
TODO: allow IBAN validation too TODO: allow IBAN validation too
""" """
default_error_messages = {
'invalid': _('Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.'),
'checksum': _('Invalid checksum for bank account number.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ESCCCField, self).__init__(r'^\d{4}[ -]?\d{4}[ -]?\d{2}[ -]?\d{10}$', super(ESCCCField, self).__init__(r'^\d{4}[ -]?\d{4}[ -]?\d{2}[ -]?\d{10}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=_('Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.'),
*args, **kwargs)
def clean(self, value): def clean(self, value):
super(ESCCCField, self).clean(value) super(ESCCCField, self).clean(value)
@ -147,7 +158,7 @@ class ESCCCField(RegexField):
if get_checksum('00' + entity + office) + get_checksum(account) == checksum: if get_checksum('00' + entity + office) + get_checksum(account) == checksum:
return value return value
else: else:
raise ValidationError, _('Invalid checksum for bank account number.') raise ValidationError, self.error_messages['checksum']
class ESRegionSelect(Select): class ESRegionSelect(Select):
""" """

View File

@ -8,11 +8,12 @@ from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.utils.translation import ugettext from django.utils.translation import ugettext
class FIZipCodeField(RegexField): class FIZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(FIZipCodeField, self).__init__(r'^\d{5}$', super(FIZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext('Enter a zip code in the format XXXXX.'),
*args, **kwargs)
class FIMunicipalitySelect(Select): class FIMunicipalitySelect(Select):
""" """
@ -23,6 +24,10 @@ class FIMunicipalitySelect(Select):
super(FIMunicipalitySelect, self).__init__(attrs, choices=MUNICIPALITY_CHOICES) super(FIMunicipalitySelect, self).__init__(attrs, choices=MUNICIPALITY_CHOICES)
class FISocialSecurityNumber(Field): class FISocialSecurityNumber(Field):
default_error_messages = {
'invalid': ugettext('Enter a valid Finnish social security number.'),
}
def clean(self, value): def clean(self, value):
super(FISocialSecurityNumber, self).clean(value) super(FISocialSecurityNumber, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
@ -37,9 +42,9 @@ class FISocialSecurityNumber(Field):
(?P<serial>(\d{3})) (?P<serial>(\d{3}))
(?P<checksum>[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE) (?P<checksum>[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE)
if not result: if not result:
raise ValidationError(ugettext('Enter a valid Finnish social security number.')) raise ValidationError(self.error_messages['invalid'])
gd = result.groupdict() gd = result.groupdict()
checksum = int(gd['date'] + gd['serial']) checksum = int(gd['date'] + gd['serial'])
if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper(): if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper():
return u'%s' % value.upper() return u'%s' % value.upper()
raise ValidationError(ugettext('Enter a valid Finnish social security number.')) raise ValidationError(self.error_messages['invalid'])

View File

@ -11,11 +11,13 @@ import re
phone_digits_re = re.compile(r'^0\d(\s|\.)?(\d{2}(\s|\.)?){3}\d{2}$') phone_digits_re = re.compile(r'^0\d(\s|\.)?(\d{2}(\s|\.)?){3}\d{2}$')
class FRZipCodeField(RegexField): class FRZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(FRZipCodeField, self).__init__(r'^\d{5}$', super(FRZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext('Enter a zip code in the format XXXXX.'),
*args, **kwargs)
class FRPhoneNumberField(Field): class FRPhoneNumberField(Field):
""" """
@ -24,6 +26,10 @@ class FRPhoneNumberField(Field):
'0X.XX.XX.XX.XX' and '0XXXXXXXXX' validate but are corrected to '0X.XX.XX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
'0X XX XX XX XX'. '0X XX XX XX XX'.
""" """
default_error_messages = {
'invalid': u'Phone numbers must be in 0X XX XX XX XX format.',
}
def clean(self, value): def clean(self, value):
super(FRPhoneNumberField, self).clean(value) super(FRPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
@ -32,7 +38,7 @@ class FRPhoneNumberField(Field):
m = phone_digits_re.search(value) m = phone_digits_re.search(value)
if m: if m:
return u'%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10]) return u'%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10])
raise ValidationError(u'Phone numbers must be in 0X XX XX XX XX format.') raise ValidationError(self.error_messages['invalid'])
class FRDepartmentSelect(Select): class FRDepartmentSelect(Select):
""" """

View File

@ -10,11 +10,13 @@ import re
class INZipCodeField(RegexField): class INZipCodeField(RegexField):
default_error_messages = {
'invalid': gettext(u'Enter a zip code in the format XXXXXXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(INZipCodeField, self).__init__(r'^\d{6}$', super(INZipCodeField, self).__init__(r'^\d{6}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=gettext(u'Enter a zip code in the format XXXXXXX.'),
*args, **kwargs)
class INStateField(Field): class INStateField(Field):
""" """
@ -22,6 +24,10 @@ class INStateField(Field):
abbreviation. It normalizes the input to the standard two-letter vehicle abbreviation. It normalizes the input to the standard two-letter vehicle
registration abbreviation for the given state or union territory registration abbreviation for the given state or union territory
""" """
default_error_messages = {
'invalid': u'Enter a Indian state or territory.',
}
def clean(self, value): def clean(self, value):
from in_states import STATES_NORMALIZED from in_states import STATES_NORMALIZED
super(INStateField, self).clean(value) super(INStateField, self).clean(value)
@ -36,7 +42,7 @@ class INStateField(Field):
return smart_unicode(STATES_NORMALIZED[value.strip().lower()]) return smart_unicode(STATES_NORMALIZED[value.strip().lower()])
except KeyError: except KeyError:
pass pass
raise ValidationError(u'Enter a Indian state or territory.') raise ValidationError(self.error_messages['invalid'])
class INStateSelect(Select): class INStateSelect(Select):
""" """

View File

@ -13,10 +13,14 @@ class ISIdNumberField(RegexField):
Icelandic identification number (kennitala). This is a number every citizen Icelandic identification number (kennitala). This is a number every citizen
of Iceland has. of Iceland has.
""" """
default_error_messages = {
'invalid': ugettext('Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.'),
'checksum': ugettext(u'The Icelandic identification number is not valid.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
error_msg = ugettext('Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.')
kwargs['min_length'],kwargs['max_length'] = 10,11 kwargs['min_length'],kwargs['max_length'] = 10,11
super(ISIdNumberField, self).__init__(r'^\d{6}(-| )?\d{4}$', error_message=error_msg, *args, **kwargs) super(ISIdNumberField, self).__init__(r'^\d{6}(-| )?\d{4}$', *args, **kwargs)
def clean(self, value): def clean(self, value):
value = super(ISIdNumberField, self).clean(value) value = super(ISIdNumberField, self).clean(value)
@ -28,7 +32,7 @@ class ISIdNumberField(RegexField):
if self._validate(value): if self._validate(value):
return self._format(value) return self._format(value)
else: else:
raise ValidationError(ugettext(u'The Icelandic identification number is not valid.')) raise ValidationError(self.error_messages['checksum'])
def _canonify(self, value): def _canonify(self, value):
""" """

View File

@ -10,11 +10,12 @@ from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check
import re import re
class ITZipCodeField(RegexField): class ITZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a valid zip code.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ITZipCodeField, self).__init__(r'^\d{5}$', super(ITZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext('Enter a valid zip code.'),
*args, **kwargs)
class ITRegionSelect(Select): class ITRegionSelect(Select):
""" """
@ -38,11 +39,13 @@ class ITSocialSecurityNumberField(RegexField):
For reference see http://www.agenziaentrate.it/ and search for For reference see http://www.agenziaentrate.it/ and search for
'Informazioni sulla codificazione delle persone fisiche'. 'Informazioni sulla codificazione delle persone fisiche'.
""" """
err_msg = ugettext(u'Enter a valid Social Security number.') default_error_messages = {
'invalid': ugettext(u'Enter a valid Social Security number.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ITSocialSecurityNumberField, self).__init__(r'^\w{3}\s*\w{3}\s*\w{5}\s*\w{5}$', super(ITSocialSecurityNumberField, self).__init__(r'^\w{3}\s*\w{3}\s*\w{5}\s*\w{5}$',
max_length=None, min_length=None, error_message=self.err_msg, max_length=None, min_length=None, *args, **kwargs)
*args, **kwargs)
def clean(self, value): def clean(self, value):
value = super(ITSocialSecurityNumberField, self).clean(value) value = super(ITSocialSecurityNumberField, self).clean(value)
@ -52,26 +55,29 @@ class ITSocialSecurityNumberField(RegexField):
try: try:
check_digit = ssn_check_digit(value) check_digit = ssn_check_digit(value)
except ValueError: except ValueError:
raise ValidationError(self.err_msg) raise ValidationError(self.error_messages['invalid'])
if not value[15] == check_digit: if not value[15] == check_digit:
raise ValidationError(self.err_msg) raise ValidationError(self.error_messages['invalid'])
return value return value
class ITVatNumberField(Field): class ITVatNumberField(Field):
""" """
A form field that validates Italian VAT numbers (partita IVA). A form field that validates Italian VAT numbers (partita IVA).
""" """
default_error_messages = {
'invalid': ugettext(u'Enter a valid VAT number.'),
}
def clean(self, value): def clean(self, value):
value = super(ITVatNumberField, self).clean(value) value = super(ITVatNumberField, self).clean(value)
if value == u'': if value == u'':
return value return value
err_msg = ugettext(u'Enter a valid VAT number.')
try: try:
vat_number = int(value) vat_number = int(value)
except ValueError: except ValueError:
raise ValidationError(err_msg) raise ValidationError(self.error_messages['invalid'])
vat_number = str(vat_number).zfill(11) vat_number = str(vat_number).zfill(11)
check_digit = vat_number_check_digit(vat_number[0:10]) check_digit = vat_number_check_digit(vat_number[0:10])
if not vat_number[10] == check_digit: if not vat_number[10] == check_digit:
raise ValidationError(err_msg) raise ValidationError(self.error_messages['invalid'])
return smart_unicode(vat_number) return smart_unicode(vat_number)

View File

@ -15,11 +15,13 @@ class JPPostalCodeField(RegexField):
Accepts 7 digits, with or without a hyphen. Accepts 7 digits, with or without a hyphen.
""" """
default_error_messages = {
'invalid': ugettext('Enter a postal code in the format XXXXXXX or XXX-XXXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(JPPostalCodeField, self).__init__(r'^\d{3}-\d{4}$|^\d{7}$', super(JPPostalCodeField, self).__init__(r'^\d{3}-\d{4}$|^\d{7}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext('Enter a postal code in the format XXXXXXX or XXX-XXXX.'),
*args, **kwargs)
def clean(self, value): def clean(self, value):
""" """

View File

@ -17,18 +17,21 @@ class NLZipCodeField(Field):
""" """
A Dutch postal code field. A Dutch postal code field.
""" """
default_error_messages = {
'invalid': _('Enter a valid postal code'),
}
def clean(self, value): def clean(self, value):
super(NLZipCodeField, self).clean(value) super(NLZipCodeField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
msg = _('Enter a valid postal code')
value = value.strip().upper().replace(' ', '') value = value.strip().upper().replace(' ', '')
if not pc_re.search(value): if not pc_re.search(value):
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
if int(value[:4]) < 1000: if int(value[:4]) < 1000:
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
return u'%s %s' % (value[:4], value[4:]) return u'%s %s' % (value[:4], value[4:])
@ -45,12 +48,15 @@ class NLPhoneNumberField(Field):
""" """
A Dutch telephone number field. A Dutch telephone number field.
""" """
default_error_messages = {
'invalid': _('Enter a valid phone number'),
}
def clean(self, value): def clean(self, value):
super(NLPhoneNumberField, self).clean(value) super(NLPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
msg = _('Enter a valid phone number')
phone_nr = re.sub('[\-\s\(\)]', '', smart_unicode(value)) phone_nr = re.sub('[\-\s\(\)]', '', smart_unicode(value))
if len(phone_nr) == 10 and numeric_re.search(phone_nr): if len(phone_nr) == 10 and numeric_re.search(phone_nr):
@ -60,7 +66,7 @@ class NLPhoneNumberField(Field):
numeric_re.search(phone_nr[3:]): numeric_re.search(phone_nr[3:]):
return value return value
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
class NLSoFiNumberField(Field): class NLSoFiNumberField(Field):
""" """
@ -68,18 +74,20 @@ class NLSoFiNumberField(Field):
http://nl.wikipedia.org/wiki/Sofinummer http://nl.wikipedia.org/wiki/Sofinummer
""" """
default_error_messages = {
'invalid': _('Enter a valid SoFi number'),
}
def clean(self, value): def clean(self, value):
super(NLSoFiNumberField, self).clean(value) super(NLSoFiNumberField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
msg = _('Enter a valid SoFi number')
if not sofi_re.search(value): if not sofi_re.search(value):
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
if int(value) == 0: if int(value) == 0:
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
checksum = 0 checksum = 0
for i in range(9, 1, -1): for i in range(9, 1, -1):
@ -87,6 +95,6 @@ class NLSoFiNumberField(Field):
checksum -= int(value[-1]) checksum -= int(value[-1])
if checksum % 11 != 0: if checksum % 11 != 0:
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
return value return value

View File

@ -8,11 +8,13 @@ from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.utils.translation import ugettext from django.utils.translation import ugettext
class NOZipCodeField(RegexField): class NOZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(NOZipCodeField, self).__init__(r'^\d{4}$', super(NOZipCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext('Enter a zip code in the format XXXX.'),
*args, **kwargs)
class NOMunicipalitySelect(Select): class NOMunicipalitySelect(Select):
""" """
@ -27,14 +29,17 @@ class NOSocialSecurityNumber(Field):
""" """
Algorithm is documented at http://no.wikipedia.org/wiki/Personnummer Algorithm is documented at http://no.wikipedia.org/wiki/Personnummer
""" """
default_error_messages = {
'invalid': ugettext(u'Enter a valid Norwegian social security number.'),
}
def clean(self, value): def clean(self, value):
super(NOSocialSecurityNumber, self).clean(value) super(NOSocialSecurityNumber, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
msg = ugettext(u'Enter a valid Norwegian social security number.')
if not re.match(r'^\d{11}$', value): if not re.match(r'^\d{11}$', value):
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
day = int(value[:2]) day = int(value[:2])
month = int(value[2:4]) month = int(value[2:4])
@ -52,7 +57,7 @@ class NOSocialSecurityNumber(Field):
if 900 <= inum < 1000 and year2 > 39: if 900 <= inum < 1000 and year2 > 39:
self.birthday = datetime.date(1900+year2, month, day) self.birthday = datetime.date(1900+year2, month, day)
except ValueError: except ValueError:
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
sexnum = int(value[8]) sexnum = int(value[8])
if sexnum % 2 == 0: if sexnum % 2 == 0:
@ -68,9 +73,9 @@ class NOSocialSecurityNumber(Field):
return sum([(a * b) for (a, b) in zip(aval, bval)]) return sum([(a * b) for (a, b) in zip(aval, bval)])
if multiply_reduce(digits, weight_1) % 11 != 0: if multiply_reduce(digits, weight_1) % 11 != 0:
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
if multiply_reduce(digits, weight_2) % 11 != 0: if multiply_reduce(digits, weight_2) % 11 != 0:
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
return value return value

View File

@ -19,6 +19,11 @@ class PEDNIField(CharField):
""" """
A field that validates `Documento Nacional de IdentidadŽ (DNI) numbers. A field that validates `Documento Nacional de IdentidadŽ (DNI) numbers.
""" """
default_error_messages = {
'invalid': ugettext("This field requires only numbers."),
'max_digits': ugettext("This field requires 8 digits."),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PEDNIField, self).__init__(max_length=8, min_length=8, *args, super(PEDNIField, self).__init__(max_length=8, min_length=8, *args,
**kwargs) **kwargs)
@ -31,9 +36,9 @@ class PEDNIField(CharField):
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
if not value.isdigit(): if not value.isdigit():
raise ValidationError(ugettext("This field requires only numbers.")) raise ValidationError(self.error_messages['invalid'])
if len(value) != 8: if len(value) != 8:
raise ValidationError(ugettext("This field requires 8 digits.")) raise ValidationError(self.error_messages['max_digits'])
return value return value
@ -42,6 +47,11 @@ class PERUCField(RegexField):
This field validates a RUC (Registro Unico de Contribuyentes). A RUC is of This field validates a RUC (Registro Unico de Contribuyentes). A RUC is of
the form XXXXXXXXXXX. the form XXXXXXXXXXX.
""" """
default_error_messages = {
'invalid': ugettext("This field requires only numbers."),
'max_digits': ugettext("This field requires 11 digits."),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PERUCField, self).__init__(max_length=11, min_length=11, *args, super(PERUCField, self).__init__(max_length=11, min_length=11, *args,
**kwargs) **kwargs)
@ -54,8 +64,8 @@ class PERUCField(RegexField):
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
if not value.isdigit(): if not value.isdigit():
raise ValidationError(ugettext("This field requires only numbers.")) raise ValidationError(self.error_messages['invalid'])
if len(value) != 11: if len(value) != 11:
raise ValidationError(ugettext("This field requires 11 digits.")) raise ValidationError(self.error_messages['max_digits'])
return value return value

View File

@ -35,16 +35,19 @@ class PLNationalIdentificationNumberField(RegexField):
The algorithm is documented at http://en.wikipedia.org/wiki/PESEL. The algorithm is documented at http://en.wikipedia.org/wiki/PESEL.
""" """
default_error_messages = {
'invalid': _(u'National Identification Number consists of 11 digits.'),
'checksum': _(u'Wrong checksum for the National Identification Number.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$', super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',
max_length=None, min_length=None, error_message=_(u'National Identification Number consists of 11 digits.'), max_length=None, min_length=None, *args, **kwargs)
*args, **kwargs)
def clean(self,value): def clean(self,value):
super(PLNationalIdentificationNumberField, self).clean(value) super(PLNationalIdentificationNumberField, self).clean(value)
if not self.has_valid_checksum(value): if not self.has_valid_checksum(value):
raise ValidationError(_(u'Wrong checksum for the National Identification Number.')) raise ValidationError(self.error_messages['checksum'])
return u'%s' % value return u'%s' % value
def has_valid_checksum(self, number): def has_valid_checksum(self, number):
@ -65,17 +68,20 @@ class PLTaxNumberField(RegexField):
Checksum algorithm based on documentation at Checksum algorithm based on documentation at
http://wipos.p.lodz.pl/zylla/ut/nip-rego.html http://wipos.p.lodz.pl/zylla/ut/nip-rego.html
""" """
default_error_messages = {
'invalid': _(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'),
'checksum': _(u'Wrong checksum for the Tax Number (NIP).'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PLTaxNumberField, self).__init__(r'^\d{3}-\d{3}-\d{2}-\d{2}$|^\d{2}-\d{2}-\d{3}-\d{3}$', super(PLTaxNumberField, self).__init__(r'^\d{3}-\d{3}-\d{2}-\d{2}$|^\d{2}-\d{2}-\d{3}-\d{3}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=_(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), *args, **kwargs)
def clean(self,value): def clean(self,value):
super(PLTaxNumberField, self).clean(value) super(PLTaxNumberField, self).clean(value)
value = re.sub("[-]", "", value) value = re.sub("[-]", "", value)
if not self.has_valid_checksum(value): if not self.has_valid_checksum(value):
raise ValidationError(_(u'Wrong checksum for the Tax Number (NIP).')) raise ValidationError(self.error_messages['checksum'])
return u'%s' % value return u'%s' % value
def has_valid_checksum(self, number): def has_valid_checksum(self, number):
@ -102,15 +108,19 @@ class PLNationalBusinessRegisterField(RegexField):
The checksum algorithm is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html The checksum algorithm is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html
""" """
default_error_messages = {
'invalid': _(u'National Business Register Number (REGON) consists of 7 or 9 digits.'),
'checksum': _(u'Wrong checksum for the National Business Register Number (REGON).'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PLNationalBusinessRegisterField, self).__init__(r'^\d{7,9}$', super(PLNationalBusinessRegisterField, self).__init__(r'^\d{7,9}$',
max_length=None, min_length=None, error_message=_(u'National Business Register Number (REGON) consists of 7 or 9 digits.'), max_length=None, min_length=None, *args, **kwargs)
*args, **kwargs)
def clean(self,value): def clean(self,value):
super(PLNationalBusinessRegisterField, self).clean(value) super(PLNationalBusinessRegisterField, self).clean(value)
if not self.has_valid_checksum(value): if not self.has_valid_checksum(value):
raise ValidationError(_(u'Wrong checksum for the National Business Register Number (REGON).')) raise ValidationError(self.error_messages['checksum'])
return u'%s' % value return u'%s' % value
def has_valid_checksum(self, number): def has_valid_checksum(self, number):
@ -142,9 +152,10 @@ class PLPostalCodeField(RegexField):
A form field that validates as Polish postal code. A form field that validates as Polish postal code.
Valid code is XX-XXX where X is digit. Valid code is XX-XXX where X is digit.
""" """
default_error_messages = {
'invalid': _(u'Enter a postal code in the format XX-XXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$', super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=_(u'Enter a postal code in the format XX-XXX.'),
*args, **kwargs)

View File

@ -26,11 +26,13 @@ class SKPostalCodeField(RegexField):
A form field that validates its input as Slovak postal code. A form field that validates its input as Slovak postal code.
Valid form is XXXXX or XXX XX, where X represents integer. Valid form is XXXXX or XXX XX, where X represents integer.
""" """
default_error_messages = {
'invalid': ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(SKPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$', super(SKPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'),
*args, **kwargs)
def clean(self, value): def clean(self, value):
""" """

View File

@ -12,11 +12,13 @@ class UKPostcodeField(RegexField):
The regular expression used is sourced from the schema for British Standard The regular expression used is sourced from the schema for British Standard
BS7666 address types: http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd BS7666 address types: http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd
""" """
default_error_messages = {
'invalid': ugettext(u'Enter a postcode. A space is required between the two postcode parts.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(UKPostcodeField, self).__init__(r'^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW]) [0-9][ABD-HJLNP-UW-Z]{2})$', super(UKPostcodeField, self).__init__(r'^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW]) [0-9][ABD-HJLNP-UW-Z]{2})$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext(u'Enter a postcode. A space is required between the two postcode parts.'),
*args, **kwargs)
class UKCountySelect(Select): class UKCountySelect(Select):
""" """

View File

@ -12,13 +12,19 @@ phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$')
ssn_re = re.compile(r"^(?P<area>\d{3})[-\ ]?(?P<group>\d{2})[-\ ]?(?P<serial>\d{4})$") ssn_re = re.compile(r"^(?P<area>\d{3})[-\ ]?(?P<group>\d{2})[-\ ]?(?P<serial>\d{4})$")
class USZipCodeField(RegexField): class USZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$', super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$',
max_length=None, min_length=None, max_length=None, min_length=None, *args, **kwargs)
error_message=ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
*args, **kwargs)
class USPhoneNumberField(Field): class USPhoneNumberField(Field):
default_error_messages = {
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
}
def clean(self, value): def clean(self, value):
super(USPhoneNumberField, self).clean(value) super(USPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
@ -27,7 +33,7 @@ class USPhoneNumberField(Field):
m = phone_digits_re.search(value) m = phone_digits_re.search(value)
if m: if m:
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.') raise ValidationError(self.error_messages['invalid'])
class USSocialSecurityNumberField(Field): class USSocialSecurityNumberField(Field):
""" """
@ -44,28 +50,31 @@ class USSocialSecurityNumberField(Field):
promotional use or distribution (e.g., the Woolworth's number or the promotional use or distribution (e.g., the Woolworth's number or the
1962 promotional number). 1962 promotional number).
""" """
default_error_messages = {
'invalid': ugettext('Enter a valid U.S. Social Security number in XXX-XX-XXXX format.'),
}
def clean(self, value): def clean(self, value):
super(USSocialSecurityNumberField, self).clean(value) super(USSocialSecurityNumberField, self).clean(value)
if value in EMPTY_VALUES: if value in EMPTY_VALUES:
return u'' return u''
msg = ugettext('Enter a valid U.S. Social Security number in XXX-XX-XXXX format.')
match = re.match(ssn_re, value) match = re.match(ssn_re, value)
if not match: if not match:
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
area, group, serial = match.groupdict()['area'], match.groupdict()['group'], match.groupdict()['serial'] area, group, serial = match.groupdict()['area'], match.groupdict()['group'], match.groupdict()['serial']
# First pass: no blocks of all zeroes. # First pass: no blocks of all zeroes.
if area == '000' or \ if area == '000' or \
group == '00' or \ group == '00' or \
serial == '0000': serial == '0000':
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
# Second pass: promotional and otherwise permanently invalid numbers. # Second pass: promotional and otherwise permanently invalid numbers.
if area == '666' or \ if area == '666' or \
(area == '987' and group == '65' and 4320 <= int(serial) <= 4329) or \ (area == '987' and group == '65' and 4320 <= int(serial) <= 4329) or \
value == '078-05-1120' or \ value == '078-05-1120' or \
value == '219-09-9999': value == '219-09-9999':
raise ValidationError(msg) raise ValidationError(self.error_messages['invalid'])
return u'%s-%s-%s' % (area, group, serial) return u'%s-%s-%s' % (area, group, serial)
class USStateField(Field): class USStateField(Field):
@ -74,6 +83,10 @@ class USStateField(Field):
It normalizes the input to the standard two-leter postal service It normalizes the input to the standard two-leter postal service
abbreviation for the given state. abbreviation for the given state.
""" """
default_error_messages = {
'invalid': u'Enter a U.S. state or territory.',
}
def clean(self, value): def clean(self, value):
from us_states import STATES_NORMALIZED from us_states import STATES_NORMALIZED
super(USStateField, self).clean(value) super(USStateField, self).clean(value)
@ -88,7 +101,7 @@ class USStateField(Field):
return STATES_NORMALIZED[value.strip().lower()].decode('ascii') return STATES_NORMALIZED[value.strip().lower()].decode('ascii')
except KeyError: except KeyError:
pass pass
raise ValidationError(u'Enter a U.S. state or territory.') raise ValidationError(self.error_messages['invalid'])
class USStateSelect(Select): class USStateSelect(Select):
""" """

View File

@ -16,10 +16,9 @@ class ZAIDField(Field):
using the Luhn checksum, and uses a simlistic (read: not entirely accurate) using the Luhn checksum, and uses a simlistic (read: not entirely accurate)
check for the birthdate check for the birthdate
""" """
default_error_messages = {
def __init__(self, *args, **kwargs): 'invalid': _(u'Enter a valid South African ID number'),
super(ZAIDField, self).__init__() }
self.error_message = _(u'Enter a valid South African ID number')
def clean(self, value): def clean(self, value):
# strip spaces and dashes # strip spaces and dashes
@ -33,7 +32,7 @@ class ZAIDField(Field):
match = re.match(id_re, value) match = re.match(id_re, value)
if not match: if not match:
raise ValidationError(self.error_message) raise ValidationError(self.error_messages['invalid'])
g = match.groupdict() g = match.groupdict()
@ -43,15 +42,18 @@ class ZAIDField(Field):
# There is no way to guess the century of a ZA ID number # There is no way to guess the century of a ZA ID number
d = date(int(g['yy']) + 2000, int(g['mm']), int(g['dd'])) d = date(int(g['yy']) + 2000, int(g['mm']), int(g['dd']))
except ValueError: except ValueError:
raise ValidationError(self.error_message) raise ValidationError(self.error_messages['invalid'])
if not luhn(value): if not luhn(value):
raise ValidationError(self.error_message) raise ValidationError(self.error_messages['invalid'])
return value return value
class ZAPostCodeField(RegexField): class ZAPostCodeField(RegexField):
default_error_messages = {
'invalid': _(u'Enter a valid South African postal code'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ZAPostCodeField, self).__init__(r'^\d{4}$', super(ZAPostCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None, max_length=None, min_length=None)
error_message=_(u'Enter a valid South African postal code'))

View File

@ -41,7 +41,7 @@ Strict RUT usage (does not allow imposible values)
>>> rut.clean('11-6') >>> rut.clean('11-6')
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.']
# valid format, bad verifier. # valid format, bad verifier.
>>> rut.clean('11.111.111-0') >>> rut.clean('11.111.111-0')
@ -53,17 +53,17 @@ ValidationError: [u'The Chilean RUT is not valid.']
>>> rut.clean('767484100') >>> rut.clean('767484100')
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.']
>>> rut.clean('78.412.790-7') >>> rut.clean('78.412.790-7')
u'78.412.790-7' u'78.412.790-7'
>>> rut.clean('8.334.6043') >>> rut.clean('8.334.6043')
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.']
>>> rut.clean('76793310-K') >>> rut.clean('76793310-K')
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.']
## CLRegionSelect ######################################################### ## CLRegionSelect #########################################################
>>> from django.contrib.localflavor.cl.forms import CLRegionSelect >>> from django.contrib.localflavor.cl.forms import CLRegionSelect