Fixed #9066 -- Added Czech localflavor. Thanks to Elvard for the contribution.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@9876 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
0c2a5ebe97
commit
b2a4377651
|
@ -0,0 +1,22 @@
|
||||||
|
"""
|
||||||
|
Czech regions, translations get from http://www.crwflags.com/fotw/Flags/cz-re.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
REGION_CHOICES = (
|
||||||
|
('PR', _('Prague')),
|
||||||
|
('CE', _('Cenral Bohemian Region')),
|
||||||
|
('SO', _('South Bohemian Region')),
|
||||||
|
('PI', _('Pilsen Region')),
|
||||||
|
('CA', _('Carlsbad Region')),
|
||||||
|
('US', _('Usti Region')),
|
||||||
|
('LB', _('Liberec Region')),
|
||||||
|
('HK', _('Hradec Region')),
|
||||||
|
('PA', _('Pardubice Region')),
|
||||||
|
('VY', _('Vysocina Region')),
|
||||||
|
('SM', _('South Moravian Region')),
|
||||||
|
('OL', _('Olomouc Region')),
|
||||||
|
('ZL', _('Zlin Region')),
|
||||||
|
('MS', _('Moravian-Silesian Region')),
|
||||||
|
)
|
|
@ -0,0 +1,140 @@
|
||||||
|
"""
|
||||||
|
Czech-specific form helpers
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.forms import ValidationError
|
||||||
|
from django.forms.fields import Select, RegexField, Field, EMPTY_VALUES
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
import re
|
||||||
|
|
||||||
|
birth_number = re.compile(r'^(?P<birth>\d{6})/?(?P<id>\d{3,4})$')
|
||||||
|
ic_number = re.compile(r'^(?P<number>\d{7})(?P<check>\d)$')
|
||||||
|
|
||||||
|
class CZRegionSelect(Select):
|
||||||
|
"""
|
||||||
|
A select widget widget with list of Czech regions as choices.
|
||||||
|
"""
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
from cz_regions import REGION_CHOICES
|
||||||
|
super(CZRegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
|
||||||
|
|
||||||
|
class CZPostalCodeField(RegexField):
|
||||||
|
"""
|
||||||
|
A form field that validates its input as Czech postal code.
|
||||||
|
Valid form is XXXXX or XXX XX, where X represents integer.
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _(u'Enter a postal code in the format XXXXX or XXX XX.'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(CZPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$',
|
||||||
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
"""
|
||||||
|
Validates the input and returns a string that contains only numbers.
|
||||||
|
Returns an empty string for empty values.
|
||||||
|
"""
|
||||||
|
v = super(CZPostalCodeField, self).clean(value)
|
||||||
|
return v.replace(' ', '')
|
||||||
|
|
||||||
|
class CZBirthNumberField(Field):
|
||||||
|
"""
|
||||||
|
Czech birth number field.
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid_format': _(u'Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX.'),
|
||||||
|
'invalid_gender': _(u'Invalid optional parameter Gender, valid values are \'f\' and \'m\''),
|
||||||
|
'invalid': _(u'Enter a valid birth number.'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(self, value, gender=None):
|
||||||
|
super(CZBirthNumberField, self).__init__(value)
|
||||||
|
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
|
||||||
|
match = re.match(birth_number, value)
|
||||||
|
if not match:
|
||||||
|
raise ValidationError(self.error_messages['invalid_format'])
|
||||||
|
|
||||||
|
birth, id = match.groupdict()['birth'], match.groupdict()['id']
|
||||||
|
|
||||||
|
# Three digits for verificatin number were used until 1. january 1954
|
||||||
|
if len(id) == 3:
|
||||||
|
return u'%s' % value
|
||||||
|
|
||||||
|
# Birth number is in format YYMMDD. Females have month value raised by 50.
|
||||||
|
# In case that all possible number are already used (for given date),
|
||||||
|
# the month field is raised by 20.
|
||||||
|
if gender is not None:
|
||||||
|
if gender == 'f':
|
||||||
|
female_const = 50
|
||||||
|
elif gender == 'm':
|
||||||
|
female_const = 0
|
||||||
|
else:
|
||||||
|
raise ValidationError(self.error_messages['invalid_gender'])
|
||||||
|
|
||||||
|
month = int(birth[2:4]) - female_const
|
||||||
|
if (not 1 <= month <= 12):
|
||||||
|
if (not 1 <= (month - 20) <= 12):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
day = int(birth[4:6])
|
||||||
|
if not (1 <= day <= 31):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
# Fourth digit has been added since 1. January 1954.
|
||||||
|
# It is modulo of dividing birth number and verification number by 11.
|
||||||
|
# If the modulo were 10, the last number was 0 (and therefore, the whole
|
||||||
|
# birth number wasn't divisable by 11. These number are no longer used (since 1985)
|
||||||
|
# and the condition 'modulo == 10' can be removed in 2085.
|
||||||
|
|
||||||
|
modulo = int(birth + id[:3]) % 11
|
||||||
|
|
||||||
|
if (modulo == int(id[-1])) or (modulo == 10 and id[-1] == '0'):
|
||||||
|
return u'%s' % value
|
||||||
|
else:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
class CZICNumberField(Field):
|
||||||
|
"""
|
||||||
|
Czech IC number field.
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _(u'Enter a valid IC number.'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
super(CZICNumberField, self).__init__(value)
|
||||||
|
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
|
||||||
|
match = re.match(ic_number, value)
|
||||||
|
if not match:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
number, check = match.groupdict()['number'], int(match.groupdict()['check'])
|
||||||
|
|
||||||
|
sum = 0
|
||||||
|
weight = 8
|
||||||
|
for digit in number:
|
||||||
|
sum += int(digit)*weight
|
||||||
|
weight -= 1
|
||||||
|
|
||||||
|
remainder = sum % 11
|
||||||
|
|
||||||
|
# remainder is equal:
|
||||||
|
# 0 or 10: last digit is 1
|
||||||
|
# 1: last digit is 0
|
||||||
|
# in other case, last digin is 11 - remainder
|
||||||
|
|
||||||
|
if (not remainder % 10 and check == 1) or \
|
||||||
|
(remainder == 1 and check == 0) or \
|
||||||
|
(check == (11 - remainder)):
|
||||||
|
return u'%s' % value
|
||||||
|
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
|
@ -44,6 +44,7 @@ Countries currently supported by :mod:`~django.contrib.localflavor` are:
|
||||||
* Brazil_
|
* Brazil_
|
||||||
* Canada_
|
* Canada_
|
||||||
* Chile_
|
* Chile_
|
||||||
|
* Czech_
|
||||||
* Finland_
|
* Finland_
|
||||||
* France_
|
* France_
|
||||||
* Germany_
|
* Germany_
|
||||||
|
@ -83,6 +84,7 @@ Here's an example of how to use them::
|
||||||
.. _Brazil: `Brazil (br)`_
|
.. _Brazil: `Brazil (br)`_
|
||||||
.. _Canada: `Canada (ca)`_
|
.. _Canada: `Canada (ca)`_
|
||||||
.. _Chile: `Chile (cl)`_
|
.. _Chile: `Chile (cl)`_
|
||||||
|
.. _Czech: `Czech (cz)`_
|
||||||
.. _Finland: `Finland (fi)`_
|
.. _Finland: `Finland (fi)`_
|
||||||
.. _France: `France (fr)`_
|
.. _France: `France (fr)`_
|
||||||
.. _Germany: `Germany (de)`_
|
.. _Germany: `Germany (de)`_
|
||||||
|
@ -231,6 +233,27 @@ Chile (``cl``)
|
||||||
A ``Select`` widget that uses a list of Chilean regions (Regiones) as its
|
A ``Select`` widget that uses a list of Chilean regions (Regiones) as its
|
||||||
choices.
|
choices.
|
||||||
|
|
||||||
|
Czech (``cz``)
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. class:: cz.forms.CZPostalCodeField
|
||||||
|
|
||||||
|
A form field that validates input as a Czech postal code. Valid formats
|
||||||
|
are XXXXX or XXX XX, where X is a digit.
|
||||||
|
|
||||||
|
.. class:: cz.forms.CZBirthNumberField
|
||||||
|
|
||||||
|
A form field that validates input as a Czech Birth Number.
|
||||||
|
A valid number must be in format XXXXXX/XXXX (slash is optional).
|
||||||
|
|
||||||
|
.. class:: cz.forms.CZICNumberField
|
||||||
|
|
||||||
|
A form field that validates input as a Czech IC number field.
|
||||||
|
|
||||||
|
.. class:: cz.forms.CZRegionSelect
|
||||||
|
|
||||||
|
A ``Select`` widget that uses a list of Czech regions as its choices.
|
||||||
|
|
||||||
Finland (``fi``)
|
Finland (``fi``)
|
||||||
================
|
================
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Tests for the contrib/localflavor/ CZ Form Fields
|
||||||
|
|
||||||
|
tests = r"""
|
||||||
|
# CZPostalCodeField #########################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.cz.forms import CZPostalCodeField
|
||||||
|
>>> f = CZPostalCodeField()
|
||||||
|
>>> f.clean('84545x')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXXXX or XXX XX.']
|
||||||
|
>>> f.clean('91909')
|
||||||
|
u'91909'
|
||||||
|
>>> f.clean('917 01')
|
||||||
|
u'91701'
|
||||||
|
>>> f.clean('12345')
|
||||||
|
u'12345'
|
||||||
|
>>> f.clean('123456')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXXXX or XXX XX.']
|
||||||
|
>>> f.clean('1234')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXXXX or XXX XX.']
|
||||||
|
>>> f.clean('123 4')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXXXX or XXX XX.']
|
||||||
|
|
||||||
|
# CZRegionSelect ############################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.cz.forms import CZRegionSelect
|
||||||
|
>>> w = CZRegionSelect()
|
||||||
|
>>> w.render('regions', 'TT')
|
||||||
|
u'<select name="regions">\n<option value="PR">Prague</option>\n<option value="CE">Cenral Bohemian Region</option>\n<option value="SO">South Bohemian Region</option>\n<option value="PI">Pilsen Region</option>\n<option value="CA">Carlsbad Region</option>\n<option value="US">Usti Region</option>\n<option value="LB">Liberec Region</option>\n<option value="HK">Hradec Region</option>\n<option value="PA">Pardubice Region</option>\n<option value="VY">Vysocina Region</option>\n<option value="SM">South Moravian Region</option>\n<option value="OL">Olomouc Region</option>\n<option value="ZL">Zlin Region</option>\n<option value="MS">Moravian-Silesian Region</option>\n</select>'
|
||||||
|
|
||||||
|
# CZBirthNumberField ########################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.cz.forms import CZBirthNumberField
|
||||||
|
>>> f = CZBirthNumberField()
|
||||||
|
>>> f.clean('880523/1237')
|
||||||
|
u'880523/1237'
|
||||||
|
>>> f.clean('8805231237')
|
||||||
|
u'8805231237'
|
||||||
|
>>> f.clean('880523/000')
|
||||||
|
u'880523/000'
|
||||||
|
>>> f.clean('880523000')
|
||||||
|
u'880523000'
|
||||||
|
>>> f.clean('882101/0011')
|
||||||
|
u'882101/0011'
|
||||||
|
>>> f.clean('880523/1237', 'm')
|
||||||
|
u'880523/1237'
|
||||||
|
>>> f.clean('885523/1231', 'f')
|
||||||
|
u'885523/1231'
|
||||||
|
>>> f.clean('123456/12')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX.']
|
||||||
|
>>> f.clean('123456/12345')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX.']
|
||||||
|
>>> f.clean('12345612')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX.']
|
||||||
|
>>> f.clean('12345612345')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX.']
|
||||||
|
>>> f.clean('881523/0000', 'm')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid birth number.']
|
||||||
|
>>> f.clean('885223/0000', 'm')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid birth number.']
|
||||||
|
>>> f.clean('881223/0000', 'f')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid birth number.']
|
||||||
|
>>> f.clean('886523/0000', 'f')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid birth number.']
|
||||||
|
>>> f.clean('880523/1239')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid birth number.']
|
||||||
|
>>> f.clean('8805231239')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid birth number.']
|
||||||
|
>>> f.clean('990101/0011')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid birth number.']
|
||||||
|
|
||||||
|
# CZICNumberField ########################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.cz.forms import CZICNumberField
|
||||||
|
>>> f = CZICNumberField()
|
||||||
|
>>> f.clean('12345679')
|
||||||
|
u'12345679'
|
||||||
|
>>> f.clean('12345601')
|
||||||
|
u'12345601'
|
||||||
|
>>> f.clean('12345661')
|
||||||
|
u'12345661'
|
||||||
|
>>> f.clean('12345610')
|
||||||
|
u'12345610'
|
||||||
|
>>> f.clean('1234567')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid IC number.']
|
||||||
|
>>> f.clean('12345660')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid IC number.']
|
||||||
|
>>> f.clean('12345600')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid IC number.']
|
||||||
|
"""
|
|
@ -10,6 +10,7 @@ from localflavor.br import tests as localflavor_br_tests
|
||||||
from localflavor.ca import tests as localflavor_ca_tests
|
from localflavor.ca import tests as localflavor_ca_tests
|
||||||
from localflavor.ch import tests as localflavor_ch_tests
|
from localflavor.ch import tests as localflavor_ch_tests
|
||||||
from localflavor.cl import tests as localflavor_cl_tests
|
from localflavor.cl import tests as localflavor_cl_tests
|
||||||
|
from localflavor.cz import tests as localflavor_cz_tests
|
||||||
from localflavor.de import tests as localflavor_de_tests
|
from localflavor.de import tests as localflavor_de_tests
|
||||||
from localflavor.es import tests as localflavor_es_tests
|
from localflavor.es import tests as localflavor_es_tests
|
||||||
from localflavor.fi import tests as localflavor_fi_tests
|
from localflavor.fi import tests as localflavor_fi_tests
|
||||||
|
@ -43,6 +44,7 @@ __test__ = {
|
||||||
'localflavor_ca_tests': localflavor_ca_tests,
|
'localflavor_ca_tests': localflavor_ca_tests,
|
||||||
'localflavor_ch_tests': localflavor_ch_tests,
|
'localflavor_ch_tests': localflavor_ch_tests,
|
||||||
'localflavor_cl_tests': localflavor_cl_tests,
|
'localflavor_cl_tests': localflavor_cl_tests,
|
||||||
|
'localflavor_cz_tests': localflavor_cz_tests,
|
||||||
'localflavor_de_tests': localflavor_de_tests,
|
'localflavor_de_tests': localflavor_de_tests,
|
||||||
'localflavor_es_tests': localflavor_es_tests,
|
'localflavor_es_tests': localflavor_es_tests,
|
||||||
'localflavor_fi_tests': localflavor_fi_tests,
|
'localflavor_fi_tests': localflavor_fi_tests,
|
||||||
|
|
Loading…
Reference in New Issue