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:
Russell Keith-Magee 2009-02-22 07:51:57 +00:00
parent 0c2a5ebe97
commit b2a4377651
6 changed files with 313 additions and 0 deletions

View File

@ -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')),
)

View File

@ -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'])

View File

@ -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``)
================ ================

View File

@ -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.']
"""

View File

@ -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,