| """ |
| Israeli-specific form helpers |
| """ |
| import re |
| |
| from django.core.exceptions import ValidationError |
| from django.core.validators import EMPTY_VALUES |
| from django.forms.fields import RegexField, Field, EMPTY_VALUES |
| from django.utils.checksums import luhn |
| from django.utils.translation import ugettext_lazy as _ |
| |
| # Israeli ID numbers consist of up to 8 digits followed by a checksum digit. |
| # Numbers which are shorter than 8 digits are effectively left-zero-padded. |
| # The checksum digit is occasionally separated from the number by a hyphen, |
| # and is calculated using the luhn algorithm. |
| # |
| # Relevant references: |
| # |
| # (hebrew) http://he.wikipedia.org/wiki/%D7%9E%D7%A1%D7%A4%D7%A8_%D7%96%D7%94%D7%95%D7%AA_(%D7%99%D7%A9%D7%A8%D7%90%D7%9C) |
| # (hebrew) http://he.wikipedia.org/wiki/%D7%A1%D7%A4%D7%A8%D7%AA_%D7%91%D7%99%D7%A7%D7%95%D7%A8%D7%AA |
| |
| id_number_re = re.compile(r'^(?P<number>\d{1,8})-?(?P<check>\d)$') |
| |
| class ILPostalCodeField(RegexField): |
| """ |
| A form field that validates its input as an Israeli postal code. |
| Valid form is XXXXX where X represents integer. |
| """ |
| |
| default_error_messages = { |
| 'invalid': _(u'Enter a postal code in the format XXXXX'), |
| } |
| |
| def __init__(self, *args, **kwargs): |
| super(ILPostalCodeField, self).__init__(r'^\d{5}$', *args, **kwargs) |
| |
| def clean(self, value): |
| if value not in EMPTY_VALUES: |
| value = value.replace(" ", "") |
| return super(ILPostalCodeField, self).clean(value) |
| |
| |
| class ILIDNumberField(Field): |
| """ |
| A form field that validates its input as an Israeli identification number. |
| Valid form is per the Israeli ID specification. |
| """ |
| |
| default_error_messages = { |
| 'invalid': _(u'Enter a valid ID number.'), |
| } |
| |
| def clean(self, value): |
| value = super(ILIDNumberField, self).clean(value) |
| |
| if value in EMPTY_VALUES: |
| return u'' |
| |
| match = id_number_re.match(value) |
| if not match: |
| raise ValidationError(self.error_messages['invalid']) |
| |
| value = match.group('number') + match.group('check') |
| if not luhn(value): |
| raise ValidationError(self.error_messages['invalid']) |
| return value |