From 5a8e40a03fd03f3ab88fb21845dd704833f3f133 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 15 Oct 2010 02:58:10 +0000 Subject: [PATCH] Fixed #11350 -- added an Israeli localflavor. Thanks to Yuval and Idan Gazit for their work on the patch. git-svn-id: http://code.djangoproject.com/svn/django/trunk@14223 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/localflavor/il/__init__.py | 0 django/contrib/localflavor/il/forms.py | 65 +++++++++++++++++++ docs/ref/contrib/localflavor.txt | 24 +++++++ tests/regressiontests/forms/localflavor/il.py | 57 ++++++++++++++++ tests/regressiontests/forms/tests.py | 1 + 5 files changed, 147 insertions(+) create mode 100644 django/contrib/localflavor/il/__init__.py create mode 100644 django/contrib/localflavor/il/forms.py create mode 100644 tests/regressiontests/forms/localflavor/il.py diff --git a/django/contrib/localflavor/il/__init__.py b/django/contrib/localflavor/il/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/django/contrib/localflavor/il/forms.py b/django/contrib/localflavor/il/forms.py new file mode 100644 index 0000000000000..bbf95d2eedeb8 --- /dev/null +++ b/django/contrib/localflavor/il/forms.py @@ -0,0 +1,65 @@ +""" +Israeli-specific form helpers +""" +import re + +from django.core.exceptions import ValidationError +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\d{1,8})-?(?P\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 is not None: + 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 diff --git a/docs/ref/contrib/localflavor.txt b/docs/ref/contrib/localflavor.txt index ae81248f24615..b2515e4fd7932 100644 --- a/docs/ref/contrib/localflavor.txt +++ b/docs/ref/contrib/localflavor.txt @@ -51,6 +51,7 @@ Countries currently supported by :mod:`~django.contrib.localflavor` are: * India_ * Indonesia_ * Ireland_ + * Israel_ * Italy_ * Japan_ * Kuwait_ @@ -99,6 +100,7 @@ Here's an example of how to use them:: .. _India: `India (in\_)`_ .. _Indonesia: `Indonesia (id)`_ .. _Ireland: `Ireland (ie)`_ +.. _Israel: `Israel (il)`_ .. _Italy: `Italy (it)`_ .. _Japan: `Japan (jp)`_ .. _Kuwait: `Kuwait (kw)`_ @@ -446,6 +448,28 @@ Indonesia (``id``) .. _NIK: http://en.wikipedia.org/wiki/Indonesian_identity_card +Israel (``il``) +=============== + +.. class: il.forms.ILPostalCodeField + + A form field that validates its input as an Israeli five-digit postal code. + +.. class:: il.forms.ILIDNumberField + + A form field that validates its input as an `Israeli identification number`_. + The output will be in the format of a 2-9 digit number, consisting of a + 1-8 digit ID number followed by a single checksum digit, calculated using the `Luhn + algorithm.`_. + + Input may contain an optional hyphen separating the ID number from the checksum + digit. + +.. _Israeli identification number: 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) +.. _Luhn algorithm: http://en.wikipedia.org/wiki/Luhn_algorithm + + + Italy (``it``) ============== diff --git a/tests/regressiontests/forms/localflavor/il.py b/tests/regressiontests/forms/localflavor/il.py new file mode 100644 index 0000000000000..8eba7a51308bd --- /dev/null +++ b/tests/regressiontests/forms/localflavor/il.py @@ -0,0 +1,57 @@ +from django.contrib.localflavor.il.forms import (ILPostalCodeField, + ILIDNumberField) +from django.core.exceptions import ValidationError +from django.utils.unittest import TestCase + + +class IsraelLocalFlavorTests(TestCase): + def test_postal_code_field(self): + f = ILPostalCodeField() + self.assertRaisesRegexp(ValidationError, + "Enter a postal code in the format XXXXX", + f.clean, "84545x" + ) + self.assertEqual(f.clean("69973"), "69973") + self.assertEqual(f.clean("699 73"), "69973") + self.assertEqual(f.clean("12345"), "12345") + self.assertRaisesRegexp(ValidationError, + "Enter a postal code in the format XXXXX", + f.clean, "123456" + ) + self.assertRaisesRegexp(ValidationError, + "Enter a postal code in the format XXXXX", + f.clean, "1234" + ) + self.assertRaisesRegexp(ValidationError, + "Enter a postal code in the format XXXXX", + f.clean, "123 4" + ) + self.assertRaises(ValidationError, f.clean, None) + + def test_id_number_field(self): + f = ILIDNumberField() + self.assertEqual(f.clean("3933742-3"), "39337423") + self.assertEqual(f.clean("39337423"), "39337423") + self.assertEqual(f.clean("039337423"), "039337423") + self.assertEqual(f.clean("03933742-3"), "039337423") + self.assertEqual(f.clean("0091"), "0091") + self.assertRaisesRegexp(ValidationError, + "Enter a valid ID number.", + f.clean, "123456789" + ) + self.assertRaisesRegexp(ValidationError, + "Enter a valid ID number.", + f.clean, "12345678-9" + ) + self.assertRaisesRegexp(ValidationError, + "Enter a valid ID number.", + f.clean, "012346578" + ) + self.assertRaisesRegexp(ValidationError, + "Enter a valid ID number.", + f.clean, "012346578-" + ) + self.assertRaisesRegexp(ValidationError, + "Enter a valid ID number.", + f.clean, "0001" + ) diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index fb41501545e60..635a989b05a65 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -17,6 +17,7 @@ from localflavor.generic import tests as localflavor_generic_tests from localflavor.id import tests as localflavor_id_tests from localflavor.ie import tests as localflavor_ie_tests +from localflavor.il import IsraelLocalFlavorTests from localflavor.is_ import tests as localflavor_is_tests from localflavor.it import tests as localflavor_it_tests from localflavor.jp import tests as localflavor_jp_tests