Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #14563 -- Added Turkish localflavor. Thanks to serkank for the …

…patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14794 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit ae7213b593b829734d00619ec7a7b45f22bdd000 1 parent 34a3863
Russell Keith-Magee authored
91  django/contrib/localflavor/tr/forms.py
... ...
@@ -0,0 +1,91 @@
  1
+"""
  2
+TR-specific Form helpers
  3
+"""
  4
+
  5
+from django.core.validators import EMPTY_VALUES
  6
+from django.forms import ValidationError
  7
+from django.forms.fields import Field, RegexField, Select, CharField
  8
+from django.utils.encoding import smart_unicode
  9
+from django.utils.translation import ugettext_lazy as _
  10
+import re
  11
+
  12
+phone_digits_re = re.compile(r'^(\+90|0)? ?(([1-9]\d{2})|\([1-9]\d{2}\)) ?([2-9]\d{2} ?\d{2} ?\d{2})$')
  13
+
  14
+class TRPostalCodeField(RegexField):
  15
+    default_error_messages = {
  16
+        'invalid': _(u'Enter a postal code in the format XXXXX.'),
  17
+    }
  18
+
  19
+    def __init__(self, *args, **kwargs):
  20
+        super(TRPostalCodeField, self).__init__(r'^\d{5}$',
  21
+            max_length=5, min_length=5, *args, **kwargs)
  22
+
  23
+    def clean(self, value):
  24
+        value = super(TRPostalCodeField, self).clean(value)
  25
+        if value in EMPTY_VALUES:
  26
+            return u''
  27
+        if len(value) != 5:
  28
+            raise ValidationError(self.error_messages['invalid'])
  29
+        province_code = int(value[:2])
  30
+        if province_code == 0 or province_code > 81:
  31
+            raise ValidationError(self.error_messages['invalid'])
  32
+        return value
  33
+
  34
+
  35
+class TRPhoneNumberField(CharField):
  36
+    default_error_messages = {
  37
+        'invalid': _(u'Phone numbers must be in 0XXX XXX XXXX format.'),
  38
+    }
  39
+
  40
+    def clean(self, value):
  41
+        super(TRPhoneNumberField, self).clean(value)
  42
+        if value in EMPTY_VALUES:
  43
+            return u''
  44
+        value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
  45
+        m = phone_digits_re.search(value)
  46
+        if m:
  47
+            return u'%s%s' % (m.group(2), m.group(4))
  48
+        raise ValidationError(self.error_messages['invalid'])
  49
+
  50
+class TRIdentificationNumberField(Field):
  51
+    """
  52
+    A Turkey Identification Number number.
  53
+	See: http://tr.wikipedia.org/wiki/T%C3%BCrkiye_Cumhuriyeti_Kimlik_Numaras%C4%B1
  54
+
  55
+    Checks the following rules to determine whether the number is valid:
  56
+
  57
+        * The number is 11-digits.
  58
+        * First digit is not 0.
  59
+        * Conforms to the following two formula:
  60
+          (sum(1st, 3rd, 5th, 7th, 9th)*7 - sum(2nd,4th,6th,8th)) % 10 = 10th digit
  61
+          sum(1st to 10th) % 10 = 11th digit
  62
+    """
  63
+    default_error_messages = {
  64
+        'invalid': _(u'Enter a valid Turkish Identification number.'),
  65
+        'not_11': _(u'Turkish Identification number must be 11 digits.'),
  66
+    }
  67
+
  68
+    def clean(self, value):
  69
+        super(TRIdentificationNumberField, self).clean(value)
  70
+        if value in EMPTY_VALUES:
  71
+            return u''
  72
+        if len(value) != 11:
  73
+            raise ValidationError(self.error_messages['not_11'])
  74
+        if not re.match(r'^\d{11}$', value):
  75
+            raise ValidationError(self.error_messages['invalid'])
  76
+        if int(value[0]) == 0:
  77
+            raise ValidationError(self.error_messages['invalid'])
  78
+        chksum = (sum([int(value[i]) for i in xrange(0,9,2)])*7-
  79
+				          sum([int(value[i]) for i in xrange(1,9,2)])) % 10
  80
+        if chksum != int(value[9]) or \
  81
+           (sum([int(value[i]) for i in xrange(10)]) % 10) != int(value[10]):
  82
+            raise ValidationError(self.error_messages['invalid'])
  83
+        return value
  84
+
  85
+class TRProvinceSelect(Select):
  86
+    """
  87
+    A Select widget that uses a list of provinces in Turkey as its choices.
  88
+    """
  89
+    def __init__(self, attrs=None):
  90
+        from tr_provinces import PROVINCE_CHOICES
  91
+        super(TRProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
89  django/contrib/localflavor/tr/tr_provinces.py
... ...
@@ -0,0 +1,89 @@
  1
+# -*- coding: utf-8 -*-
  2
+"""
  3
+This exists in this standalone file so that it's only imported into memory
  4
+when explicitly needed.
  5
+"""
  6
+
  7
+PROVINCE_CHOICES = (
  8
+    ('01', ('Adana')),
  9
+    ('02', ('Adıyaman')),
  10
+    ('03', ('Afyonkarahisar')),
  11
+    ('04', ('Ağrı')),
  12
+    ('68', ('Aksaray')),
  13
+    ('05', ('Amasya')),
  14
+    ('06', ('Ankara')),
  15
+    ('07', ('Antalya')),
  16
+    ('75', ('Ardahan')),
  17
+    ('08', ('Artvin')),
  18
+    ('09', ('Aydın')),
  19
+    ('10', ('Balıkesir')),
  20
+    ('74', ('Bartın')),
  21
+    ('72', ('Batman')),
  22
+    ('69', ('Bayburt')),
  23
+    ('11', ('Bilecik')),
  24
+    ('12', ('Bingöl')),
  25
+    ('13', ('Bitlis')),
  26
+    ('14', ('Bolu')),
  27
+    ('15', ('Burdur')),
  28
+    ('16', ('Bursa')),
  29
+    ('17', ('Çanakkale')),
  30
+    ('18', ('Çankırı')),
  31
+    ('19', ('Çorum')),
  32
+    ('20', ('Denizli')),
  33
+    ('21', ('Diyarbakır')),
  34
+    ('81', ('Düzce')),
  35
+    ('22', ('Edirne')),
  36
+    ('23', ('Elazığ')),
  37
+    ('24', ('Erzincan')),
  38
+    ('25', ('Erzurum')),
  39
+    ('26', ('Eskişehir')),
  40
+    ('27', ('Gaziantep')),
  41
+    ('28', ('Giresun')),
  42
+    ('29', ('Gümüşhane')),
  43
+    ('30', ('Hakkari')),
  44
+    ('31', ('Hatay')),
  45
+    ('76', ('Iğdır')),
  46
+    ('32', ('Isparta')),
  47
+    ('33', ('Mersin')),
  48
+    ('34', ('İstanbul')),
  49
+    ('35', ('İzmir')),
  50
+    ('78', ('Karabük')),
  51
+    ('36', ('Kars')),
  52
+    ('37', ('Kastamonu')),
  53
+    ('38', ('Kayseri')),
  54
+    ('39', ('Kırklareli')),
  55
+    ('40', ('Kırşehir')),
  56
+    ('41', ('Kocaeli')),
  57
+    ('42', ('Konya')),
  58
+    ('43', ('Kütahya')),
  59
+    ('44', ('Malatya')),
  60
+    ('45', ('Manisa')),
  61
+    ('46', ('Kahramanmaraş')),
  62
+    ('70', ('Karaman')),
  63
+    ('71', ('Kırıkkale')),
  64
+    ('79', ('Kilis')),
  65
+    ('47', ('Mardin')),
  66
+    ('48', ('Muğla')),
  67
+    ('49', ('Muş')),
  68
+    ('50', ('Nevşehir')),
  69
+    ('51', ('Niğde')),
  70
+    ('52', ('Ordu')),
  71
+    ('80', ('Osmaniye')),
  72
+    ('53', ('Rize')),
  73
+    ('54', ('Sakarya')),
  74
+    ('55', ('Samsun')),
  75
+    ('56', ('Siirt')),
  76
+    ('57', ('Sinop')),
  77
+    ('58', ('Sivas')),
  78
+    ('73', ('Şırnak')),
  79
+    ('59', ('Tekirdağ')),
  80
+    ('60', ('Tokat')),
  81
+    ('61', ('Trabzon')),
  82
+    ('62', ('Tunceli')),
  83
+    ('63', ('Şanlıurfa')),
  84
+    ('64', ('Uşak')),
  85
+    ('65', ('Van')),
  86
+    ('77', ('Yalova')),
  87
+    ('66', ('Yozgat')),
  88
+    ('67', ('Zonguldak')),
  89
+)
31  docs/ref/contrib/localflavor.txt
@@ -67,6 +67,7 @@ Countries currently supported by :mod:`~django.contrib.localflavor` are:
67 67
     * Spain_
68 68
     * Sweden_
69 69
     * Switzerland_
  70
+    * Turkey_
70 71
     * `United Kingdom`_
71 72
     * `United States of America`_
72 73
     * Uruguay_
@@ -115,6 +116,7 @@ Here's an example of how to use them::
115 116
 .. _Spain: `Spain (es)`_
116 117
 .. _Sweden: `Sweden (se)`_
117 118
 .. _Switzerland: `Switzerland (ch)`_
  119
+.. _Turkey: `Turkey (tr)`_
118 120
 .. _United Kingdom: `United Kingdom (uk)`_
119 121
 .. _United States of America: `United States of America (us)`_
120 122
 .. _Uruguay: `Uruguay (uy)`_
@@ -853,6 +855,35 @@ Switzerland (``ch``)
853 855
 
854 856
     A ``Select`` widget that uses a list of Swiss states as its choices.
855 857
 
  858
+Turkey (``tr``)
  859
+===============
  860
+
  861
+.. class:: tr.forms.TRZipCodeField
  862
+
  863
+    A form field that validates input as a Turkish zip code. Valid codes
  864
+    consist of five digits.
  865
+
  866
+.. class:: tr.forms.TRPhoneNumberField
  867
+
  868
+    A form field that validates input as a Turkish phone number. The correct
  869
+    format is 0xxx xxx xxxx. +90xxx xxx xxxx and inputs without spaces also
  870
+    validates. The result is normalized to xxx xxx xxxx format.
  871
+
  872
+.. class:: tr.forms.TRIdentificationNumberField
  873
+
  874
+    A form field that validates input as a TR identification number. A valid
  875
+    number must satisfy the following:
  876
+
  877
+    * The number consist of 11 digits.
  878
+    * The first digit cannot be 0.
  879
+    * (sum(1st, 3rd, 5th, 7th, 9th)*7 - sum(2nd,4th,6th,8th)) % 10) must be
  880
+    equal to the 10th digit.
  881
+    * (sum(1st to 10th) % 10) must be equal to the 11th digit.
  882
+
  883
+.. class:: tr.forms.TRProvinceSelect
  884
+
  885
+    A ``select`` widget that uses a list of Turkish provinces as its choices.
  886
+
856 887
 United Kingdom (``uk``)
857 888
 =======================
858 889
 
0  localflavor/tr/__init__.py b/django/contrib/localflavor/tr/__init__.py
No changes.
2  tests/regressiontests/forms/localflavor/be.py
@@ -4,7 +4,7 @@
4 4
 from django.contrib.localflavor.be.forms import (BEPostalCodeField,
5 5
     BEPhoneNumberField, BERegionSelect, BEProvinceSelect)
6 6
 
7  
-class BETests(TestCase):
  7
+class BELocalFlavorTests(TestCase):
8 8
     """
9 9
     Test case to validate BE localflavor
10 10
     """
2  tests/regressiontests/forms/localflavor/il.py
@@ -4,7 +4,7 @@
4 4
 from django.utils.unittest import TestCase
5 5
 
6 6
 
7  
-class IsraelLocalFlavorTests(TestCase):
  7
+class ILLocalFlavorTests(TestCase):
8 8
     def test_postal_code_field(self):
9 9
         f = ILPostalCodeField()
10 10
         self.assertRaisesRegexp(ValidationError,
73  tests/regressiontests/forms/localflavor/tr.py
... ...
@@ -0,0 +1,73 @@
  1
+# Tests for the contrib/localflavor/ TR form fields.
  2
+
  3
+from django.contrib.localflavor.tr import forms as trforms
  4
+from django.core.exceptions import ValidationError
  5
+from django.utils.unittest import TestCase
  6
+
  7
+class TRLocalFlavorTests(TestCase):
  8
+    def test_TRPostalCodeField(self):
  9
+        f = trforms.TRPostalCodeField()
  10
+        self.assertEqual(f.clean("06531"), "06531")
  11
+        self.assertEqual(f.clean("12345"), "12345")
  12
+        self.assertRaisesRegexp(ValidationError,
  13
+            "Enter a postal code in the format XXXXX.",
  14
+            f.clean, "a1234")
  15
+        self.assertRaisesRegexp(ValidationError,
  16
+            "Enter a postal code in the format XXXXX.",
  17
+            f.clean, "1234")
  18
+        self.assertRaisesRegexp(ValidationError,
  19
+            "Enter a postal code in the format XXXXX.",
  20
+            f.clean, "82123")
  21
+        self.assertRaisesRegexp(ValidationError,
  22
+            "Enter a postal code in the format XXXXX.",
  23
+            f.clean, "00123")
  24
+        self.assertRaisesRegexp(ValidationError,
  25
+            "Enter a postal code in the format XXXXX.",
  26
+            f.clean, "123456")
  27
+        self.assertRaisesRegexp(ValidationError,
  28
+            "Enter a postal code in the format XXXXX.",
  29
+            f.clean, "12 34")
  30
+        self.assertRaises(ValidationError, f.clean, None)
  31
+
  32
+    def test_TRPhoneNumberField(self):
  33
+        f = trforms.TRPhoneNumberField()
  34
+        self.assertEqual(f.clean("312 455 56 78"), "3124555678")
  35
+        self.assertEqual(f.clean("312 4555678"), "3124555678")
  36
+        self.assertEqual(f.clean("3124555678"), "3124555678")
  37
+        self.assertEqual(f.clean("0312 455 5678"), "3124555678")
  38
+        self.assertEqual(f.clean("0 312 455 5678"), "3124555678")
  39
+        self.assertEqual(f.clean("0 (312) 455 5678"), "3124555678")
  40
+        self.assertEqual(f.clean("+90 312 455 4567"), "3124554567")
  41
+        self.assertEqual(f.clean("+90 312 455 45 67"), "3124554567")
  42
+        self.assertEqual(f.clean("+90 (312) 4554567"), "3124554567")
  43
+        self.assertRaisesRegexp(ValidationError,
  44
+            'Phone numbers must be in 0XXX XXX XXXX format.',
  45
+            f.clean, "1234 233 1234")
  46
+        self.assertRaisesRegexp(ValidationError,
  47
+            'Phone numbers must be in 0XXX XXX XXXX format.',
  48
+            f.clean, "0312 233 12345")
  49
+        self.assertRaisesRegexp(ValidationError,
  50
+            'Phone numbers must be in 0XXX XXX XXXX format.',
  51
+            f.clean, "0312 233 123")
  52
+        self.assertRaisesRegexp(ValidationError,
  53
+            'Phone numbers must be in 0XXX XXX XXXX format.',
  54
+            f.clean, "0312 233 xxxx")
  55
+
  56
+    def test_TRIdentificationNumberField(self):
  57
+        f = trforms.TRIdentificationNumberField()
  58
+        self.assertEqual(f.clean("10000000146"), "10000000146")
  59
+        self.assertRaisesRegexp(ValidationError,
  60
+            'Enter a valid Turkish Identification number.',
  61
+            f.clean, "10000000136")
  62
+        self.assertRaisesRegexp(ValidationError,
  63
+            'Enter a valid Turkish Identification number.',
  64
+            f.clean, "10000000147")
  65
+        self.assertRaisesRegexp(ValidationError,
  66
+            'Turkish Identification number must be 11 digits.',
  67
+            f.clean, "123456789")
  68
+        self.assertRaisesRegexp(ValidationError,
  69
+            'Enter a valid Turkish Identification number.',
  70
+            f.clean, "1000000014x")
  71
+        self.assertRaisesRegexp(ValidationError,
  72
+            'Enter a valid Turkish Identification number.',
  73
+            f.clean, "x0000000146")
5  tests/regressiontests/forms/localflavortests.py
@@ -14,7 +14,7 @@
14 14
 from localflavor.generic import tests as localflavor_generic_tests
15 15
 from localflavor.id import tests as localflavor_id_tests
16 16
 from localflavor.ie import tests as localflavor_ie_tests
17  
-from localflavor.il import IsraelLocalFlavorTests
  17
+from localflavor.il import ILLocalFlavorTests
18 18
 from localflavor.is_ import tests as localflavor_is_tests
19 19
 from localflavor.it import tests as localflavor_it_tests
20 20
 from localflavor.jp import tests as localflavor_jp_tests
@@ -25,12 +25,13 @@
25 25
 from localflavor.ro import tests as localflavor_ro_tests
26 26
 from localflavor.se import tests as localflavor_se_tests
27 27
 from localflavor.sk import tests as localflavor_sk_tests
  28
+from localflavor.tr import TRLocalFlavorTests
28 29
 from localflavor.uk import tests as localflavor_uk_tests
29 30
 from localflavor.us import tests as localflavor_us_tests
30 31
 from localflavor.uy import tests as localflavor_uy_tests
31 32
 from localflavor.za import tests as localflavor_za_tests
32 33
 
33  
-from localflavor.be import BETests
  34
+from localflavor.be import BELocalFlavorTests
34 35
 
35 36
 __test__ = {
36 37
     'localflavor_ar_tests': localflavor_ar_tests,
9  tests/regressiontests/forms/tests/__init__.py
@@ -11,5 +11,10 @@
11 11
 from validators import TestFieldWithValidators
12 12
 from widgets import *
13 13
 
14  
-from regressiontests.forms.localflavortests import (__test__, BETests,
15  
-    DELocalFlavorTests, IsraelLocalFlavorTests)
  14
+from regressiontests.forms.localflavortests import (
  15
+    __test__,
  16
+    BELocalFlavorTests,
  17
+    DELocalFlavorTests,
  18
+    ILLocalFlavorTests,
  19
+    TRLocalFlavorTests
  20
+)

0 notes on commit ae7213b

Please sign in to comment.
Something went wrong with that request. Please try again.