Django

Code

root/django/trunk/django/contrib/localflavor/de/forms.py

Revision 7971, 3.1 kB (checked in by jacob, 3 months ago)

Fixed #7741: django.newforms is now django.forms. This is obviously a backwards-incompatible change. There's a warning upon import of django.newforms itself, but deeper imports will raise errors.

  • Property svn:eol-style set to native
Line 
1 """
2 DE-specific Form helpers
3 """
4
5 from django.forms import ValidationError
6 from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
7 from django.utils.translation import ugettext_lazy as _
8 import re
9
10 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})$")
11
12 class DEZipCodeField(RegexField):
13     default_error_messages = {
14         'invalid': _('Enter a zip code in the format XXXXX.'),
15     }
16     def __init__(self, *args, **kwargs):
17         super(DEZipCodeField, self).__init__(r'^\d{5}$',
18             max_length=None, min_length=None, *args, **kwargs)
19
20 class DEStateSelect(Select):
21     """
22     A Select widget that uses a list of DE states as its choices.
23     """
24     def __init__(self, attrs=None):
25         from de_states import STATE_CHOICES
26         super(DEStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
27
28 class DEIdentityCardNumberField(Field):
29     """
30     A German identity card number.
31
32     Checks the following rules to determine whether the number is valid:
33
34         * Conforms to the XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.
35         * No group consists entirely of zeroes.
36         * Included checksums match calculated checksums
37
38     Algorithm is documented at http://de.wikipedia.org/wiki/Personalausweis
39     """
40     default_error_messages = {
41         'invalid': _('Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.'),
42     }
43
44     def has_valid_checksum(self, number):
45         given_number, given_checksum = number[:-1], number[-1]
46         calculated_checksum = 0
47         fragment = ""
48         parameter = 7
49
50         for i in range(len(given_number)):
51             fragment = str(int(given_number[i]) * parameter)
52             if fragment.isalnum():
53                 calculated_checksum += int(fragment[-1])
54             if parameter == 1:
55                 parameter = 7
56             elif parameter == 3:
57                 parameter = 1
58             elif parameter ==7:
59                 parameter = 3
60
61         return str(calculated_checksum)[-1] == given_checksum
62
63     def clean(self, value):
64         super(DEIdentityCardNumberField, self).clean(value)
65         if value in EMPTY_VALUES:
66             return u''
67         match = re.match(id_re, value)
68         if not match:
69             raise ValidationError(self.error_messages['invalid'])
70
71         gd = match.groupdict()
72         residence, origin = gd['residence'], gd['origin']
73         birthday, validity, checksum = gd['birthday'], gd['validity'], gd['checksum']
74
75         if residence == '0000000000' or birthday == '0000000' or validity == '0000000':
76             raise ValidationError(self.error_messages['invalid'])
77
78         all_digits = u"%s%s%s%s" % (residence, birthday, validity, checksum)
79         if not self.has_valid_checksum(residence) or not self.has_valid_checksum(birthday) or \
80             not self.has_valid_checksum(validity) or not self.has_valid_checksum(all_digits):
81                 raise ValidationError(self.error_messages['invalid'])
82
83         return u'%s%s-%s-%s-%s' % (residence, origin, birthday, validity, checksum)
Note: See TracBrowser for help on using the browser.