PageRenderTime 48ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/django/contrib/localflavor/cz/forms.py

https://bitbucket.org/elissawolf92/hackpack
Python | 145 lines | 116 code | 11 blank | 18 comment | 7 complexity | 1aecdf1859fda0ca0a22f40787b0d352 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0
  1. """
  2. Czech-specific form helpers
  3. """
  4. from django.core.validators import EMPTY_VALUES
  5. from django.forms import ValidationError
  6. from django.forms.fields import Select, RegexField, Field
  7. from django.utils.translation import ugettext_lazy as _
  8. import re
  9. birth_number = re.compile(r'^(?P<birth>\d{6})/?(?P<id>\d{3,4})$')
  10. ic_number = re.compile(r'^(?P<number>\d{7})(?P<check>\d)$')
  11. class CZRegionSelect(Select):
  12. """
  13. A select widget widget with list of Czech regions as choices.
  14. """
  15. def __init__(self, attrs=None):
  16. from cz_regions import REGION_CHOICES
  17. super(CZRegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
  18. class CZPostalCodeField(RegexField):
  19. """
  20. A form field that validates its input as Czech postal code.
  21. Valid form is XXXXX or XXX XX, where X represents integer.
  22. """
  23. default_error_messages = {
  24. 'invalid': _(u'Enter a postal code in the format XXXXX or XXX XX.'),
  25. }
  26. def __init__(self, *args, **kwargs):
  27. super(CZPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$',
  28. max_length=None, min_length=None, *args, **kwargs)
  29. def clean(self, value):
  30. """
  31. Validates the input and returns a string that contains only numbers.
  32. Returns an empty string for empty values.
  33. """
  34. v = super(CZPostalCodeField, self).clean(value)
  35. return v.replace(' ', '')
  36. class CZBirthNumberField(Field):
  37. """
  38. Czech birth number field.
  39. """
  40. default_error_messages = {
  41. 'invalid_format': _(u'Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX.'),
  42. 'invalid_gender': _(u'Invalid optional parameter Gender, valid values are \'f\' and \'m\''),
  43. 'invalid': _(u'Enter a valid birth number.'),
  44. }
  45. def clean(self, value, gender=None):
  46. super(CZBirthNumberField, self).clean(value)
  47. if value in EMPTY_VALUES:
  48. return u''
  49. match = re.match(birth_number, value)
  50. if not match:
  51. raise ValidationError(self.error_messages['invalid_format'])
  52. birth, id = match.groupdict()['birth'], match.groupdict()['id']
  53. # Three digits for verification number were used until 1. january 1954
  54. if len(id) == 3:
  55. return u'%s' % value
  56. # Birth number is in format YYMMDD. Females have month value raised by 50.
  57. # In case that all possible number are already used (for given date),
  58. # the month field is raised by 20.
  59. if gender is not None:
  60. import warnings
  61. warnings.warn(
  62. "Support for validating the gender of a CZ Birth number has been deprecated.",
  63. PendingDeprecationWarning)
  64. if gender == 'f':
  65. female_const = 50
  66. elif gender == 'm':
  67. female_const = 0
  68. else:
  69. raise ValidationError(self.error_messages['invalid_gender'])
  70. month = int(birth[2:4]) - female_const
  71. if (not 1 <= month <= 12):
  72. if (not 1 <= (month - 20) <= 12):
  73. raise ValidationError(self.error_messages['invalid'])
  74. day = int(birth[4:6])
  75. if not (1 <= day <= 31):
  76. raise ValidationError(self.error_messages['invalid'])
  77. # Fourth digit has been added since 1. January 1954.
  78. # It is modulo of dividing birth number and verification number by 11.
  79. # If the modulo were 10, the last number was 0 (and therefore, the whole
  80. # birth number wasn't divisable by 11. These number are no longer used (since 1985)
  81. # and the condition 'modulo == 10' can be removed in 2085.
  82. modulo = int(birth + id[:3]) % 11
  83. if (modulo == int(id[-1])) or (modulo == 10 and id[-1] == '0'):
  84. return u'%s' % value
  85. else:
  86. raise ValidationError(self.error_messages['invalid'])
  87. class CZICNumberField(Field):
  88. """
  89. Czech IC number field.
  90. """
  91. default_error_messages = {
  92. 'invalid': _(u'Enter a valid IC number.'),
  93. }
  94. def clean(self, value):
  95. super(CZICNumberField, self).clean(value)
  96. if value in EMPTY_VALUES:
  97. return u''
  98. match = re.match(ic_number, value)
  99. if not match:
  100. raise ValidationError(self.error_messages['invalid'])
  101. number, check = match.groupdict()['number'], int(match.groupdict()['check'])
  102. sum = 0
  103. weight = 8
  104. for digit in number:
  105. sum += int(digit)*weight
  106. weight -= 1
  107. remainder = sum % 11
  108. # remainder is equal:
  109. # 0 or 10: last digit is 1
  110. # 1: last digit is 0
  111. # in other case, last digin is 11 - remainder
  112. if (not remainder % 10 and check == 1) or \
  113. (remainder == 1 and check == 0) or \
  114. (check == (11 - remainder)):
  115. return u'%s' % value
  116. raise ValidationError(self.error_messages['invalid'])