From 61947f0635bdf5a4043caa2562e085058b2d19a8 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Sun, 2 Dec 2007 18:43:01 +0000 Subject: [PATCH] Fixed #3961 -- Added South African localflavor. Thanks, Russell Cloran. git-svn-id: http://code.djangoproject.com/svn/django/trunk@6843 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/localflavor/za/__init__.py | 0 django/contrib/localflavor/za/forms.py | 57 +++++++++++++++++++ django/contrib/localflavor/za/za_provinces.py | 13 +++++ tests/regressiontests/forms/localflavor/za.py | 40 +++++++++++++ tests/regressiontests/forms/tests.py | 2 + 5 files changed, 112 insertions(+) create mode 100644 django/contrib/localflavor/za/__init__.py create mode 100644 django/contrib/localflavor/za/forms.py create mode 100644 django/contrib/localflavor/za/za_provinces.py create mode 100644 tests/regressiontests/forms/localflavor/za.py diff --git a/django/contrib/localflavor/za/__init__.py b/django/contrib/localflavor/za/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django/contrib/localflavor/za/forms.py b/django/contrib/localflavor/za/forms.py new file mode 100644 index 0000000000..b04b7cf6ab --- /dev/null +++ b/django/contrib/localflavor/za/forms.py @@ -0,0 +1,57 @@ +""" +South Africa-specific Form helpers +""" + +from django.newforms import ValidationError +from django.newforms.fields import Field, RegexField, EMPTY_VALUES +from django.utils.checksums import luhn +from django.utils.translation import gettext as _ +import re +from datetime import date + +id_re = re.compile(r'^(?P\d\d)(?P\d\d)(?P
\d\d)(?P\d{4})(?P\d{3})') + +class ZAIDField(Field): + """A form field for South African ID numbers -- the checksum is validated + using the Luhn checksum, and uses a simlistic (read: not entirely accurate) + check for the birthdate + """ + + def __init__(self, *args, **kwargs): + super(ZAIDField, self).__init__() + self.error_message = _(u'Enter a valid South African ID number') + + def clean(self, value): + # strip spaces and dashes + value = value.strip().replace(' ', '').replace('-', '') + + super(ZAIDField, self).clean(value) + + if value in EMPTY_VALUES: + return u'' + + match = re.match(id_re, value) + + if not match: + raise ValidationError(self.error_message) + + g = match.groupdict() + + try: + # The year 2000 is conveniently a leapyear. + # This algorithm will break in xx00 years which aren't leap years + # There is no way to guess the century of a ZA ID number + d = date(int(g['yy']) + 2000, int(g['mm']), int(g['dd'])) + except ValueError: + raise ValidationError(self.error_message) + + if not luhn(value): + raise ValidationError(self.error_message) + + return value + +class ZAPostCodeField(RegexField): + def __init__(self, *args, **kwargs): + super(ZAPostCodeField, self).__init__(r'^\d{4}$', + max_length=None, min_length=None, + error_message=_(u'Enter a valid South African postal code')) diff --git a/django/contrib/localflavor/za/za_provinces.py b/django/contrib/localflavor/za/za_provinces.py new file mode 100644 index 0000000000..0bc6fe14b3 --- /dev/null +++ b/django/contrib/localflavor/za/za_provinces.py @@ -0,0 +1,13 @@ +from django.utils.translation import gettext_lazy as _ + +PROVINCE_CHOICES = ( + ('EC', _('Eastern Cape')), + ('FS', _('Free State')), + ('GP', _('Gauteng')), + ('KN', _('KwaZulu-Natal')), + ('LP', _('Limpopo')), + ('MP', _('Mpumalanga')), + ('NC', _('Northern Cape')), + ('NW', _('North West')), + ('WC', _('Western Cape')), +) diff --git a/tests/regressiontests/forms/localflavor/za.py b/tests/regressiontests/forms/localflavor/za.py new file mode 100644 index 0000000000..a948964b8d --- /dev/null +++ b/tests/regressiontests/forms/localflavor/za.py @@ -0,0 +1,40 @@ +tests = r""" +# ZAIDField ################################################################# + +ZAIDField validates that the date is a valid birthdate and that the value +has a valid checksum. It allows spaces and dashes, and returns a plain +string of digits. +>>> from django.contrib.localflavor.za.forms import ZAIDField +>>> f = ZAIDField() +>>> f.clean('0002290001003') +'0002290001003' +>>> f.clean('000229 0001 003') +'0002290001003' +>>> f.clean('0102290001001') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid South African ID number'] +>>> f.clean('811208') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid South African ID number'] +>>> f.clean('0002290001004') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid South African ID number'] + +# ZAPostCodeField ########################################################### +>>> from django.contrib.localflavor.za.forms import ZAPostCodeField +>>> f = ZAPostCodeField() +>>> f.clean('abcd') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid South African postal code'] +>>> f.clean('0000') +u'0000' +>>> f.clean(' 7530') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid South African postal code'] + +""" diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 6acd4f2e1d..bb0e30b874 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -22,6 +22,7 @@ from localflavor.pl import tests as localflavor_pl_tests from localflavor.sk import tests as localflavor_sk_tests from localflavor.uk import tests as localflavor_uk_tests from localflavor.us import tests as localflavor_us_tests +from localflavor.za import tests as localflavor_za_tests from regressions import tests as regression_tests from util import tests as util_tests from widgets import tests as widgets_tests @@ -50,6 +51,7 @@ __test__ = { 'localflavor_sk_tests': localflavor_sk_tests, 'localflavor_uk_tests': localflavor_uk_tests, 'localflavor_us_tests': localflavor_us_tests, + 'localflavor_za_tests': localflavor_za_tests, 'regression_tests': regression_tests, 'util_tests': util_tests, 'widgets_tests': widgets_tests,