Add Django-1.2.1
[frozenviper.git] / Django-1.2.1 / django / contrib / localflavor / cz / forms.py
blobe980569c70dfae3d9358b2c315ccfa36102a52c2
1 """
2 Czech-specific form helpers
3 """
5 from django.core.validators import EMPTY_VALUES
6 from django.forms import ValidationError
7 from django.forms.fields import Select, RegexField, Field
8 from django.utils.translation import ugettext_lazy as _
9 import re
11 birth_number = re.compile(r'^(?P<birth>\d{6})/?(?P<id>\d{3,4})$')
12 ic_number = re.compile(r'^(?P<number>\d{7})(?P<check>\d)$')
14 class CZRegionSelect(Select):
15 """
16 A select widget widget with list of Czech regions as choices.
17 """
18 def __init__(self, attrs=None):
19 from cz_regions import REGION_CHOICES
20 super(CZRegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
22 class CZPostalCodeField(RegexField):
23 """
24 A form field that validates its input as Czech postal code.
25 Valid form is XXXXX or XXX XX, where X represents integer.
26 """
27 default_error_messages = {
28 'invalid': _(u'Enter a postal code in the format XXXXX or XXX XX.'),
31 def __init__(self, *args, **kwargs):
32 super(CZPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$',
33 max_length=None, min_length=None, *args, **kwargs)
35 def clean(self, value):
36 """
37 Validates the input and returns a string that contains only numbers.
38 Returns an empty string for empty values.
39 """
40 v = super(CZPostalCodeField, self).clean(value)
41 return v.replace(' ', '')
43 class CZBirthNumberField(Field):
44 """
45 Czech birth number field.
46 """
47 default_error_messages = {
48 'invalid_format': _(u'Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX.'),
49 'invalid_gender': _(u'Invalid optional parameter Gender, valid values are \'f\' and \'m\''),
50 'invalid': _(u'Enter a valid birth number.'),
53 def clean(self, value, gender=None):
54 super(CZBirthNumberField, self).__init__(value)
56 if value in EMPTY_VALUES:
57 return u''
59 match = re.match(birth_number, value)
60 if not match:
61 raise ValidationError(self.error_messages['invalid_format'])
63 birth, id = match.groupdict()['birth'], match.groupdict()['id']
65 # Three digits for verificatin number were used until 1. january 1954
66 if len(id) == 3:
67 return u'%s' % value
69 # Birth number is in format YYMMDD. Females have month value raised by 50.
70 # In case that all possible number are already used (for given date),
71 # the month field is raised by 20.
72 if gender is not None:
73 if gender == 'f':
74 female_const = 50
75 elif gender == 'm':
76 female_const = 0
77 else:
78 raise ValidationError(self.error_messages['invalid_gender'])
80 month = int(birth[2:4]) - female_const
81 if (not 1 <= month <= 12):
82 if (not 1 <= (month - 20) <= 12):
83 raise ValidationError(self.error_messages['invalid'])
85 day = int(birth[4:6])
86 if not (1 <= day <= 31):
87 raise ValidationError(self.error_messages['invalid'])
89 # Fourth digit has been added since 1. January 1954.
90 # It is modulo of dividing birth number and verification number by 11.
91 # If the modulo were 10, the last number was 0 (and therefore, the whole
92 # birth number wasn't divisable by 11. These number are no longer used (since 1985)
93 # and the condition 'modulo == 10' can be removed in 2085.
95 modulo = int(birth + id[:3]) % 11
97 if (modulo == int(id[-1])) or (modulo == 10 and id[-1] == '0'):
98 return u'%s' % value
99 else:
100 raise ValidationError(self.error_messages['invalid'])
102 class CZICNumberField(Field):
104 Czech IC number field.
106 default_error_messages = {
107 'invalid': _(u'Enter a valid IC number.'),
110 def clean(self, value):
111 super(CZICNumberField, self).__init__(value)
113 if value in EMPTY_VALUES:
114 return u''
116 match = re.match(ic_number, value)
117 if not match:
118 raise ValidationError(self.error_messages['invalid'])
120 number, check = match.groupdict()['number'], int(match.groupdict()['check'])
122 sum = 0
123 weight = 8
124 for digit in number:
125 sum += int(digit)*weight
126 weight -= 1
128 remainder = sum % 11
130 # remainder is equal:
131 # 0 or 10: last digit is 1
132 # 1: last digit is 0
133 # in other case, last digin is 11 - remainder
135 if (not remainder % 10 and check == 1) or \
136 (remainder == 1 and check == 0) or \
137 (check == (11 - remainder)):
138 return u'%s' % value
140 raise ValidationError(self.error_messages['invalid'])