def __call__(self, value): if value is None: return value value = value.upper() # Length is 8 or 11. bic_length = len(value) if bic_length != 8 and bic_length != 11: raise ValidationError( _('BIC codes have either 8 or 11 characters.')) # First 4 letters are A - Z. institution_code = value[:4] for x in institution_code: if x not in string.ascii_uppercase: raise ValidationError( _('%s is not a valid institution code.') % institution_code) # Letters 5 and 6 consist of an ISO 3166-1 alpha-2 country code. country_code = value[4:6] if country_code not in ISO_3166_1_ALPHA2_COUNTRY_CODES: raise ValidationError( _('%s is not a valid country code.') % country_code)
def __call__(self, value): """ Validates the IBAN value using the official IBAN validation algorithm. https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN """ if value is None: return value value = value.upper().replace(' ', '').replace('-', '') # Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid. country_code = value[:2] if country_code in self.validation_countries: if self.validation_countries[country_code] != len(value): msg_params = { 'country_code': country_code, 'number': self.validation_countries[country_code] } raise ValidationError( _('%(country_code)s IBANs must contain %(number)s characters.' ) % msg_params) else: raise ValidationError( _('%s is not a valid country code for IBAN.') % country_code) if self.include_countries and country_code not in self.include_countries: raise ValidationError( _('%s IBANs are not allowed in this field.') % country_code) if self.iban_checksum(value) != value[2:4]: raise ValidationError(_('Not a valid IBAN.'))
class VATINValidator: """ A validator for VAT identification numbers. Currently only supports European VIES VAT identification numbers. See See https://en.wikipedia.org/wiki/VAT_identification_number """ messages = { 'country_code': _('%(country_code)s is not a valid country code.'), 'vatin': _('%(vatin)s is not a valid VAT identification number.'), } def __call__(self, value): country_code, number = self.clean(value) try: match = re.match(VATIN_PATTERN_MAP[country_code], value) if not match: raise ValidationError(self.messages['vatin'], code='vatin', params={'vatin': value}) except KeyError: raise ValidationError(self.messages['country_code'], code='country_code', params={'country_code': country_code}) def clean(self, value): """Return tuple of country code and number.""" return value[:VATIN_COUNTRY_CODE_LENGTH], value[ VATIN_COUNTRY_CODE_LENGTH:]
class CUProvinceField(CharValidator): """ A form field for a Cuban province. The input is validated against a dictionary which includes names and abbreviations. It normalizes the input to the standard abbreviation for the given province. .. versionadded:: 1.6 """ default_error_messages = { 'invalid': _('Enter a Cuban province.'), } description = _("Cuban provinces (three uppercase letters)") def __init__(self, *args, **kwargs): kwargs['choices'] = PROVINCE_CHOICES kwargs['max_length'] = 3 super(CUProvinceField, self).__init__(*args, **kwargs) def clean(self, value): super(CUProvinceField, self).clean(value) if value in self.empty_values: return self.empty_value try: return PROVINCE_NORMALIZED[value.strip().lower()] except KeyError: pass raise ValidationError(self.error_messages['invalid'])
class GBPostalCodeField(CharValidator): """ A form field that validates its input is a UK postcode. 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 The value is uppercased and a space added in the correct place, if required. """ default_error_messages = { 'invalid': _('Enter a valid postal code.'), } outcode_pattern = '[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW])' incode_pattern = '[0-9][ABD-HJLNP-UW-Z]{2}' postcode_regex = re.compile(r'^(GIR 0AA|%s %s)$' % (outcode_pattern, incode_pattern)) space_regex = re.compile(r' *(%s)$' % incode_pattern) def clean(self, value): value = super(GBPostalCodeField, self).clean(value) if value in self.empty_values: return self.empty_value postcode = value.upper().strip() # Put a single space before the incode (second part). postcode = self.space_regex.sub(r' \1', postcode) if not self.postcode_regex.search(postcode): raise ValidationError(self.error_messages['invalid']) return postcode
class USStateField(CharValidator): """ A form field that validates its input is a U.S. state, territory, or COFA territory. The input is validated against a dictionary which includes names and abbreviations. It normalizes the input to the standard two-letter postal service abbreviation for the given state. """ default_error_messages = { 'invalid': _('Enter a U.S. state or territory.'), } def clean(self, value): from .us_states import STATES_NORMALIZED super(USStateField, self).clean(value) if value in EMPTY_VALUES: return self.empty_value try: value = value.strip().lower() except AttributeError: pass else: try: return STATES_NORMALIZED[value.strip().lower()] except KeyError: pass raise ValidationError(self.error_messages['invalid'])
class NLPostalCodeField(RegexValidator): """ Validation for Dutch zip codes. .. versionadded:: 1.3 """ default_error_messages = { 'invalid': _('Enter a valid postal code in the format NNNN XX.') } def __init__(self): super(NLPostalCodeField, self).__init__(regex=r'^\d{4} ?[A-Z]{2}$') def clean(self, value): value = value.upper() value = super(NLPostalCodeField, self).clean(value) if int(value[:4]) < 1000: raise ValidationError(self.error_messages['invalid']) if isinstance(value, six.string_types): value = value.upper().replace(' ', '') if len(value) == 6: value = '%s %s' % (value[:4], value[4:]) return super(NLPostalCodeField, self).clean(value)
class HRPostalCodeField(CharValidator): """ Postal code of Croatia field. It consists of exactly five digits ranging from 10000 to possibly less than 60000. http://www.posta.hr/main.aspx?id=66 """ default_error_messages = { 'invalid': _('Enter a valid 5 digit postal code.'), } def clean(self, value): super(HRPostalCodeField, self).clean(value) if value in EMPTY_VALUES: return self.empty_value value = value.strip() if not postal_code_re.search(value): raise ValidationError(self.error_messages['invalid']) # Make sure the number is in valid range. if not 9999 < int(value) < 60000: raise ValidationError(self.error_messages['invalid']) return '%s' % value
class TRPostalCodeField(RegexValidator): """ A form field that validates input as a Turkish zip code. Valid codes consist of five digits. """ default_error_messages = { 'invalid': _('Enter a valid postal code in the format XXXXX.'), } def __init__(self, max_length=5, min_length=5, *args, **kwargs): super(TRPostalCodeField, self).__init__( r'^\d{5}$', max_length=max_length, min_length=min_length, *args, **kwargs ) def clean(self, value): value = super(TRPostalCodeField, self).clean(value) if value in self.empty_values: return self.empty_value if len(value) != 5: raise ValidationError(self.error_messages['invalid']) province_code = int(value[:2]) if province_code == 0 or province_code > 81: raise ValidationError(self.error_messages['invalid']) return value
class EANValidator(object): """ A generic validator for EAN like codes with the last digit being the checksum. http://en.wikipedia.org/wiki/International_Article_Number_(EAN) """ message = _('Not a valid EAN code.') def __init__(self, strip_nondigits=False, message=None): if message is not None: self.message = message self.strip_nondigits = strip_nondigits def __eq__(self, other): return (not hasattr(self, 'message') or self.message == other.message) and \ self.strip_nondigits == other.strip_nondigits def __call__(self, value): if value is None: return value if self.strip_nondigits: value = re.compile(r'[^\d]+').sub('', value) if not checksums.ean(value): raise ValidationError(self.message, code='invalid')
class DKPostalCodeField(ChoiceField): """An Input widget that uses a list of Danish postal codes as valid input.""" default_error_messages = { 'invalid': _('Enter a valid postal code in the format XXXX.') } choices = DK_POSTALCODES
class SKPostalCodeField(RegexValidator): """ A form field that validates its input as Slovak postal code. Valid form is XXXXX or XXX XX, where X represents integer. """ default_error_messages = { 'invalid': _('Enter a valid postal code in the format XXXXX or XXX XX.'), } def __init__(self, *args, **kwargs): super(SKPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$', *args, **kwargs) def clean(self, value): """ Validates the input and returns a string that contains only numbers. Returns an empty string for empty values. """ value = super(SKPostalCodeField, self).clean(value) if value in self.empty_values: return self.empty_value return value.replace(' ', '')
class ARPostalCodeField(RegexValidator): """ Accepts a 'classic' NNNN Postal Code or a CPA. See: * http://www.correoargentino.com.ar/cpa/que_es * http://www.correoargentino.com.ar/cpa/como_escribirlo """ default_error_messages = { 'invalid': _('Enter a valid postal code in the format NNNN or ANNNNAAA.'), } def __init__(self, max_length=8, min_length=4, *args, **kwargs): super(ARPostalCodeField, self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$', max_length=max_length, min_length=min_length, *args, **kwargs) def clean(self, value): value = super(ARPostalCodeField, self).clean(value) if value in self.empty_values: return self.empty_value if len(value) not in (4, 8): raise ValidationError(self.error_messages['invalid']) if len(value) == 8: return '%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper()) return value
class INStateField(CharValidator): """ A form field that validates its input is a Indian state name or abbreviation. It normalizes the input to the standard two-letter vehicle registration abbreviation for the given state or union territory .. versionchanged:: 1.1 Added Telangana to list of states. More details at https://en.wikipedia.org/wiki/Telangana#Bifurcation_of_Andhra_Pradesh """ default_error_messages = { 'invalid': _('Enter an Indian state or territory.'), } def clean(self, value): value = super(INStateField, self).clean(value) if value in EMPTY_VALUES: return self.empty_value try: value = value.strip().lower() except AttributeError: pass else: try: return str(STATES_NORMALIZED[value.strip().lower()]) except KeyError: pass raise ValidationError(self.error_messages['invalid'])
class IDPostalCodeField(CharValidator): """ An Indonesian post code field. http://id.wikipedia.org/wiki/Kode_pos """ default_error_messages = { 'invalid': _('Enter a valid 5 digit postal code.'), } def clean(self, value): super(IDPostalCodeField, self).clean(value) if value in EMPTY_VALUES: return self.empty_value value = value.strip() if not postcode_re.search(value): raise ValidationError(self.error_messages['invalid']) if int(value) < 10110: raise ValidationError(self.error_messages['invalid']) # 1xxx0 if value[0] == '1' and value[4] != '0': raise ValidationError(self.error_messages['invalid']) return '%s' % (value, )
class SIPostalCodeField(ChoiceField): """Slovenian post codes field.""" default_error_messages = { 'invalid': _('Enter a valid postal code in the format XXXX.'), } def __init__(self, *args, **kwargs): kwargs.setdefault('choices', SI_POSTALCODES_CHOICES) super(SIPostalCodeField, self).__init__(*args, **kwargs)
class ISPostalCodeField(CharValidator): """Validates Icelandic postal codes as its choices.""" default_error_messages = { 'invalid': _('Enter a valid 3 digit postal code.'), } def __init__(self): super(ISPostalCodeField, self).__init__(min_length=None, max_length=None, choices=IS_POSTALCODES)
class CUPostalCodeField(RegexValidator): """ A form field for a Cuban postal Code. Taken from : http://mapanet.eu/Postal_Codes/?C=CU The Cuban postal code is a combination of 5 digits non begin with 0. .. versionadded:: 1.6 """ default_error_messages = { 'invalid': _('Enter a valid postal code in the format XXXXX.'), } description = _("Cuban postal code") def __init__(self, *args, **kwargs): kwargs['max_length'] = 5 super(CUPostalCodeField, self).__init__(r'^[1-9]\d{4}$', *args, **kwargs)
class SGPostalCodeField(RegexValidator): """ Singapore post code field. Assumed to be 6 digits. """ default_error_messages = { 'invalid': _('Enter a 6-digit postal code.'), } def __init__(self, *args, **kwargs): super(SGPostalCodeField, self).__init__(r'^\d{6}$', *args, **kwargs)
class EEPostalCodeField(RegexValidator): """ A form field that validates input as a Estonian zip code. Valid codes consist of five digits; first digit cannot be 0. """ default_error_messages = { 'invalid': _('Enter a valid postal code in the format XXXXX.'), } def __init__(self, *args, **kwargs): super(EEPostalCodeField, self).__init__(zipcode, *args, **kwargs)
class RUPostalCodeField(RegexValidator): """ Russian Postal code field. Format: XXXXXX, where X is any digit, and first digit is not zero. """ default_error_messages = { 'invalid': _('Enter a valid postal code in the format XXXXXX.'), } def __init__(self, *args, **kwargs): super(RUPostalCodeField, self).__init__(r'^\d{6}$', *args, **kwargs)
class ITPostalCodeField(RegexValidator): """ A form field that validates input as an Italian zip code. Valid codes must have five digits. """ default_error_messages = { 'invalid': _('Enter a 5 digit ZIP code.'), } def __init__(self, *args, **kwargs): super(ITPostalCodeField, self).__init__(r'^\d{5}$', *args, **kwargs)
class CNPostalCodeField(RegexValidator): """ A form field that validates input as postal codes in mainland China. Valid codes are in the format of XXXXXX where X is a digit. """ default_error_messages = { 'invalid': _('Enter a valid postal code in the format XXXXXX.'), } def __init__(self, *args, **kwargs): super(CNPostalCodeField, self).__init__(POST_CODE_RE, *args, **kwargs)
class PLPostalCodeField(RegexValidator): """ A form field that validates as Polish postal code. Valid code is XX-XXX where X is digit. """ default_error_messages = { 'invalid': _('Enter a valid postal code in the format XX-XXX.'), } def __init__(self, *args, **kwargs): super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$', *args, **kwargs)
class NOPostalCodeField(RegexValidator): """ A form field that validates input as a Norwegian zip code. Valid codes have four digits. """ default_error_messages = { 'invalid': _('Enter a valid postal code in the format XXXX.'), } def __init__(self, *args, **kwargs): super(NOPostalCodeField, self).__init__(r'^\d{4}$', *args, **kwargs)
class AUPostalCodeField(RegexValidator): """ Australian post code field. Assumed to be 4 digits. Northern Territory 3-digit postcodes should have leading zero. """ default_error_messages = { 'invalid': _('Enter a 4 digit postal code.'), } def __init__(self, max_length=4, *args, **kwargs): super(AUPostalCodeField, self).__init__(r'^\d{4}$', max_length=max_length, *args, **kwargs)