Ticket #11626: my_localflavor.diff
File my_localflavor.diff, 21.3 KB (added by , 15 years ago) |
---|
-
django/contrib/localflavor/my/my_states.py
1 """ 2 A list of Malaysian states for use as `choices` in a form or model field. 3 """ 4 5 from django.utils.translation import gettext_lazy as _ 6 7 STATE_CHOICES = ( 8 ('JHR', _(u'Johor')), 9 ('KDH', _(u'Kedah')), 10 ('KTN', _(u'Kelantan')), 11 ('MLK', _(u'Melaka')), 12 ('NSN', _(u'Negeri Sembilan')), 13 ('PHG', _(u'Pahang ')), 14 ('PNG', _(u'Pulau Pinang')), 15 ('PRK', _(u'Perak')), 16 ('PLS', _(u'Perlis')), 17 ('SGR', _(u'Selangor')), 18 ('TRG', _(u'Terengganu')), 19 ('SBH', _(u'Sabah')), 20 ('SRW', _(u'Sarawak')), 21 ('KUL', _(u'W.P Kuala Lumpur')), 22 ('LBN', _(u'W.P Labuan')), 23 ('PJY', _(u'W.P Putrajaya')), 24 ('WP', _(u'Wilayah Persekutuan')), 25 ) -
django/contrib/localflavor/my/models.py
1 """ 2 Malaysia-specific model fields. 3 """ 4 5 from django.conf import settings 6 from django.db.models.fields import Field 7 8 class IdentityCardNumberField(Field): 9 """ 10 A ``CharField`` validates its input is a Malaysian Identity Card number. 11 """ 12 def get_internal_type(self): 13 return "IdentityCardNumberField" 14 15 def db_type(self): 16 if settings.DATABASE_ENGINE == 'oracle': 17 return 'VARCHAR2(14)' 18 else: 19 return 'varchar(14)' 20 21 def formfield(self, **kwargs): 22 from django.contrib.localflavor.my.forms import MYIdentityCardNumberField 23 defaults = {'widget': MYIdentityCardNumberField} 24 defaults.update(kwargs) 25 return super(MYIdentityCardNumberField, self).formfield(**defaults) 26 27 class PostCodeField(Field): 28 """ 29 A model field that forms represent as a ``forms.MYPostCodeField`` and 30 validates its input is a Malaysian postcode. 31 """ 32 def get_internal_type(self): 33 return "PostCodeField" 34 35 def db_type(self): 36 if settings.DATABASE_ENGINE == 'oracle': 37 return 'CHAR(5)' 38 else: 39 return 'varchar(5)' 40 41 def formfield(self, **kwargs): 42 from django.contrib.localflavor.my.forms import MYPostCodeField 43 defaults = {'widget': MYPostCodeField} 44 defaults.update(kwargs) 45 return super(MYPostCodeField, self).formfield(**defaults) 46 47 class PhoneNumberField(Field): 48 """ 49 A model field that forms represent as a ``forms.MYPhoneNumberField`` and 50 validates its input is a Malaysian phone number. 51 """ 52 def get_internal_type(self): 53 return "PhoneNumberField" 54 55 def db_type(self): 56 if settings.DATABASE_ENGINE == 'oracle': 57 return 'VARCHAR2(14)' 58 else: 59 return 'varchar(14)' 60 61 def formfield(self, **kwargs): 62 from django.contrib.localflavor.my.forms import MYPhoneNumberField 63 defaults = {'widget': MYPhoneNumberField} 64 defaults.update(kwargs) 65 return super(MYPhoneNumberField, self).formfield(**defaults) 66 67 class StateField(Field): 68 """ 69 A model field that forms represent as a ``forms.MYStateField`` and stores the 70 three-letter Malaysian state abbreviation in the database. 71 """ 72 def get_internal_type(self): 73 return "StateField" 74 75 def db_type(self): 76 if settings.DATABASE_ENGINE == 'oracle': 77 return 'CHAR(3)' 78 else: 79 return 'varchar(3)' 80 81 def formfield(self, **kwargs): 82 from django.contrib.localflavor.my.forms import MYStateSelect 83 defaults = {'widget': MYStateSelect} 84 defaults.update(kwargs) 85 return super(MYStateSelect, self).formfield(**defaults) -
django/contrib/localflavor/my/my_bpcodes.py
1 """ 2 A list of valid BP (Birth Place) codes in the Malaysian Identity Card number. 3 4 Source: http://en.wikipedia.org/wiki/MyKad#BP_codes_-_Codes_representing_place_of_birth 5 """ 6 7 BP_CODES = ('00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', 8 '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', 9 '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', 10 '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', 11 '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60', '61', '62', 12 '63', '64', '65', '66', '67', '68', '74', '75', '76', '77', '78', '79', '82', 13 '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93') -
django/contrib/localflavor/my/forms.py
1 """ 2 Malaysia-specific form helpers. 3 """ 4 5 from django.forms import ValidationError 6 from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES 7 from django.utils.encoding import smart_unicode 8 from django.utils.translation import gettext_lazy as _ 9 import re 10 11 ic_re = re.compile(r'^(?P<dob>\d{6})-?(?P<bp>\d{2})-?(?P<serial>\d{4})$') 12 phone_re = re.compile(r'^(\+?6?)(\d{2,3}-?)(\d{6,8})$') 13 14 class MYIdentityCardNumberField(Field): 15 """ 16 A form field that validates its input is a valid Malaysian Identity Card number. 17 (YYMMDD-BP-XXXX) 18 19 The regular expression used is sourced from: http://en.wikipedia.org/wiki/MyKad 20 21 Takes one extra optional argument: 22 23 .. attribute:: MYIdentityCardNumberField.check_bp_code 24 25 If ``True``, field will validate the BP digits is a valid BP (birth place) 26 code (see above Wikipedia link for more information). Default: ``True`` 27 """ 28 default_error_messages = { 29 'invalid': _(u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'), 30 } 31 32 def __init__(self, *args, **kwargs): 33 self.check_bp_code = kwargs.get('check_bp_code', True) 34 if 'check_bp_code' in kwargs: 35 del kwargs['check_bp_code'] 36 Field.__init__(self, *args, **kwargs) 37 38 def clean(self, value): 39 super(MYIdentityCardNumberField, self).clean(value) 40 if value in EMPTY_VALUES: 41 return u'' 42 match = re.match(ic_re, value) 43 if not match: 44 raise ValidationError(self.error_messages['invalid']) 45 dob, bp, serial = match.groupdict()['dob'], match.groupdict()['bp'], match.groupdict()['serial'] 46 47 # DOB is a valid date 48 from datetime import date 49 try: 50 yy, mm, dd = int(dob[0:2]), int(dob[2:4]), int(dob[4:]) 51 d = date(yy, mm, dd) 52 except ValueError: 53 raise ValidationError(self.error_messages['invalid']) 54 55 # BP is a valid birth place code 56 if self.check_bp_code: 57 from my_bpcodes import BP_CODES 58 if not bp in BP_CODES: 59 raise ValidationError(self.error_messages['invalid']) 60 61 return u'%s-%s-%s' % (dob, bp, serial) 62 63 class MYPostCodeField(RegexField): 64 """ 65 A form field that validates its input is a 5-digit Malaysian postcode. 66 """ 67 default_error_messages = { 68 'invalid': _(u'Enter a postcode in the format XXXXX.') 69 } 70 71 def __init__(self, *args, **kwargs): 72 super(MYPostCodeField, self).__init__(r'^\d{5}$', 73 max_length=None, min_length=None, *args, **kwargs) 74 75 class MYPhoneNumberField(Field): 76 """ 77 A form field that validates its input is a Malaysian phone number. 78 79 Accepts phone numbers in the format XXX-XXXXXXXX, with or without an 80 international country code prefix (+6) 81 """ 82 default_error_messages = { 83 'invalid': _(u'Enter a phone number in the format XXX-XXXXXXXX.') 84 } 85 86 def clean(self, value): 87 super(MYPhoneNumberField, self).clean(value) 88 if value in EMPTY_VALUES: 89 return u'' 90 value = re.sub('(\(|\)|\s+)', '', smart_unicode(value)) 91 m = phone_re.search(value) 92 if m: 93 return u'%s%s%s' % (m.group(1), m.group(2), m.group(3)) 94 raise ValidationError(self.error_messages['invalid']) 95 96 class MYStateSelect(Select): 97 """ 98 A Select widget that uses a list of Malaysian states as its choices. 99 """ 100 def __init__(self, attrs=None): 101 from my_states import STATE_CHOICES 102 super(MYStateSelect, self).__init__(attrs, choices=STATE_CHOICES) -
tests/regressiontests/forms/localflavor/my.py
1 # Tests for the contrib/localflavor/ MY form fields. 2 3 tests = r""" 4 # MYIdentityCardNumberField ################################################### 5 6 >>> from django.contrib.localflavor.my.forms import MYIdentityCardNumberField 7 >>> f = MYIdentityCardNumberField() 8 >>> f.clean('821226-10-5007') 9 u'821226-10-5007' 10 >>> f.clean('821226105007') 11 u'821226-10-5007' 12 >>> f.clean('821X2-1@-5007') # non-numeric 13 Traceback (most recent call last): 14 ... 15 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 16 >>> f.clean('82122-10-5007') # missing digits 17 Traceback (most recent call last): 18 ... 19 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 20 >>> f.clean('821232-10-5007') # invalid date 21 Traceback (most recent call last): 22 ... 23 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 24 >>> f.clean('821226-99-5007') # invalid BP code 25 Traceback (most recent call last): 26 ... 27 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 28 >>> f.clean(None) 29 Traceback (most recent call last): 30 ... 31 ValidationError: [u'This field is required.'] 32 >>> f.clean('') 33 Traceback (most recent call last): 34 ... 35 ValidationError: [u'This field is required.'] 36 37 >>> from django.contrib.localflavor.my.forms import MYIdentityCardNumberField 38 >>> f = MYIdentityCardNumberField(required=False) 39 >>> f.clean('821226-10-5007') 40 u'821226-10-5007' 41 >>> f.clean('821226105007') 42 u'821226-10-5007' 43 >>> f.clean('821X2-1@-5007') # non-numeric 44 Traceback (most recent call last): 45 ... 46 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 47 >>> f.clean('82122-10-5007') # missing digits 48 Traceback (most recent call last): 49 ... 50 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 51 >>> f.clean('821232-10-5007') # invalid date 52 Traceback (most recent call last): 53 ... 54 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 55 >>> f.clean('821226-99-5007') # invalid BP code 56 Traceback (most recent call last): 57 ... 58 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 59 >>> f.clean(None) 60 u'' 61 >>> f.clean('') 62 u'' 63 64 >>> from django.contrib.localflavor.my.forms import MYIdentityCardNumberField 65 >>> f = MYIdentityCardNumberField(check_bp_code=False) 66 >>> f.clean('821226-10-5007') 67 u'821226-10-5007' 68 >>> f.clean('821226105007') 69 u'821226-10-5007' 70 >>> f.clean('821X2-1@-5007') # non-numeric 71 Traceback (most recent call last): 72 ... 73 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 74 >>> f.clean('82122-10-5007') # missing digits 75 Traceback (most recent call last): 76 ... 77 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 78 >>> f.clean('821232-10-5007') # invalid date 79 Traceback (most recent call last): 80 ... 81 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 82 >>> f.clean('821226-99-5007') # ignores invalid BP code 83 u'821226-99-5007' 84 >>> f.clean(None) 85 Traceback (most recent call last): 86 ... 87 ValidationError: [u'This field is required.'] 88 >>> f.clean('') 89 Traceback (most recent call last): 90 ... 91 ValidationError: [u'This field is required.'] 92 93 >>> from django.contrib.localflavor.my.forms import MYIdentityCardNumberField 94 >>> f = MYIdentityCardNumberField(check_bp_code=False, required=False) 95 >>> f.clean('821226-10-5007') 96 u'821226-10-5007' 97 >>> f.clean('821226105007') 98 u'821226-10-5007' 99 >>> f.clean('821X2-1@-5007') # non-numeric 100 Traceback (most recent call last): 101 ... 102 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 103 >>> f.clean('82122-10-5007') # missing digits 104 Traceback (most recent call last): 105 ... 106 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 107 >>> f.clean('821232-10-5007') # invalid date 108 Traceback (most recent call last): 109 ... 110 ValidationError: [u'Enter a valid Identity Card number in XXXXXX-XX-XXXX format.'] 111 >>> f.clean('821226-99-5007') # ignores invalid BP code 112 u'821226-99-5007' 113 >>> f.clean(None) 114 u'' 115 >>> f.clean('') 116 u'' 117 118 # MYPostCodeField ############################################################# 119 120 >>> from django.contrib.localflavor.my.forms import MYPostCodeField 121 >>> f = MYPostCodeField() 122 >>> f.clean('41150') 123 u'41150' 124 >>> f.clean(41150) 125 u'41150' 126 >>> f.clean(4115) 127 Traceback (most recent call last): 128 ... 129 ValidationError: [u'Enter a postcode in the format XXXXX.'] 130 >>> f.clean(None) 131 Traceback (most recent call last): 132 ... 133 ValidationError: [u'This field is required.'] 134 >>> f.clean('') 135 Traceback (most recent call last): 136 ... 137 ValidationError: [u'This field is required.'] 138 139 >>> from django.contrib.localflavor.my.forms import MYPostCodeField 140 >>> f = MYPostCodeField(required=False) 141 >>> f.clean('41150') 142 u'41150' 143 >>> f.clean(41150) 144 u'41150' 145 >>> f.clean(4115) 146 Traceback (most recent call last): 147 ... 148 ValidationError: [u'Enter a postcode in the format XXXXX.'] 149 >>> f.clean(None) 150 u'' 151 >>> f.clean('') 152 u'' 153 154 # MYPhoneNumberField ########################################################## 155 156 >>> from django.contrib.localflavor.my.forms import MYPhoneNumberField 157 >>> f = MYPhoneNumberField() 158 >>> f.clean('+603-33430633') # full, 2-digit prefix 159 u'+603-33430633' 160 >>> f.clean('+60333430633') # no dash 161 u'+60333430633' 162 >>> f.clean('03-33430633') # no icc 163 u'03-33430633' 164 >>> f.clean('0333430633') # no dash, no icc 165 u'0333430633' 166 >>> f.clean('+6016-3469486') # full, 3-digit prefix (mobile phones) 167 u'+6016-3469486' 168 >>> f.clean('+60163469486') # no dash 169 u'+60163469486' 170 >>> f.clean('016-3469486') # no icc 171 u'016-3469486' 172 >>> f.clean('0163469486') # no dash, no icc 173 u'0163469486' 174 >>> f.clean('0163-469486') 175 Traceback (most recent call last): 176 ... 177 ValidationError: [u'Enter a phone number in the format XXX-XXXXXXXX.'] 178 >>> f.clean('016-46948') 179 Traceback (most recent call last): 180 ... 181 ValidationError: [u'Enter a phone number in the format XXX-XXXXXXXX.'] 182 >>> f.clean('016-469486789') 183 Traceback (most recent call last): 184 ... 185 ValidationError: [u'Enter a phone number in the format XXX-XXXXXXXX.'] 186 >>> f.clean(None) 187 Traceback (most recent call last): 188 ... 189 ValidationError: [u'This field is required.'] 190 >>> f.clean('') 191 Traceback (most recent call last): 192 ... 193 ValidationError: [u'This field is required.'] 194 195 >>> from django.contrib.localflavor.my.forms import MYPhoneNumberField 196 >>> f = MYPhoneNumberField(required=False) 197 >>> f.clean('+603-33430633') # full, 2-digit prefix 198 u'+603-33430633' 199 >>> f.clean('+60333430633') # no dash 200 u'+60333430633' 201 >>> f.clean('03-33430633') # no icc 202 u'03-33430633' 203 >>> f.clean('0333430633') # no dash, no icc 204 u'0333430633' 205 >>> f.clean('+6016-3469486') # full, 3-digit prefix (mobile phones) 206 u'+6016-3469486' 207 >>> f.clean('+60163469486') # no dash 208 u'+60163469486' 209 >>> f.clean('016-3469486') # no icc 210 u'016-3469486' 211 >>> f.clean('0163469486') # no dash, no icc 212 u'0163469486' 213 >>> f.clean('0163-469486') 214 Traceback (most recent call last): 215 ... 216 ValidationError: [u'Enter a phone number in the format XXX-XXXXXXXX.'] 217 >>> f.clean('016-46948') 218 Traceback (most recent call last): 219 ... 220 ValidationError: [u'Enter a phone number in the format XXX-XXXXXXXX.'] 221 >>> f.clean('016-469486789') 222 Traceback (most recent call last): 223 ... 224 ValidationError: [u'Enter a phone number in the format XXX-XXXXXXXX.'] 225 >>> f.clean(None) 226 u'' 227 >>> f.clean('') 228 u'' 229 230 # MYStateSelect ########################################################## 231 232 >>> from django.contrib.localflavor.my.forms import MYStateSelect 233 >>> f = MYStateSelect() 234 >>> print f.render('state', 'SGR') 235 <select name="state"> 236 <option value="JHR">Johor</option> 237 <option value="KDH">Kedah</option> 238 <option value="KTN">Kelantan</option> 239 <option value="MLK">Melaka</option> 240 <option value="NSN">Negeri Sembilan</option> 241 <option value="PHG">Pahang </option> 242 <option value="PNG">Pulau Pinang</option> 243 <option value="PRK">Perak</option> 244 <option value="PLS">Perlis</option> 245 <option value="SGR" selected="selected">Selangor</option> 246 <option value="TRG">Terengganu</option> 247 <option value="SBH">Sabah</option> 248 <option value="SRW">Sarawak</option> 249 <option value="KUL">W.P Kuala Lumpur</option> 250 <option value="LBN">W.P Labuan</option> 251 <option value="PJY">W.P Putrajaya</option> 252 <option value="WP">Wilayah Persekutuan</option> 253 </select> 254 """ -
tests/regressiontests/forms/tests.py
19 19 from localflavor.is_ import tests as localflavor_is_tests 20 20 from localflavor.it import tests as localflavor_it_tests 21 21 from localflavor.jp import tests as localflavor_jp_tests 22 from localflavor.my import tests as localflavor_my_tests 22 23 from localflavor.nl import tests as localflavor_nl_tests 23 24 from localflavor.pl import tests as localflavor_pl_tests 24 25 from localflavor.ro import tests as localflavor_ro_tests … … 53 54 'localflavor_is_tests': localflavor_is_tests, 54 55 'localflavor_it_tests': localflavor_it_tests, 55 56 'localflavor_jp_tests': localflavor_jp_tests, 57 'localflavor_my_tests': localflavor_my_tests, 56 58 'localflavor_nl_tests': localflavor_nl_tests, 57 59 'localflavor_pl_tests': localflavor_pl_tests, 58 60 'localflavor_ro_tests': localflavor_ro_tests, -
docs/ref/contrib/localflavor.txt
52 52 * India_ 53 53 * Italy_ 54 54 * Japan_ 55 * Malaysia_ 55 56 * Mexico_ 56 57 * `The Netherlands`_ 57 58 * Norway_ … … 93 94 .. _India: `India (in\_)`_ 94 95 .. _Italy: `Italy (it)`_ 95 96 .. _Japan: `Japan (jp)`_ 97 .. _Malaysia: `Malaysia (my)`_ 96 98 .. _Mexico: `Mexico (mx)`_ 97 99 .. _Norway: `Norway (no)`_ 98 100 .. _Peru: `Peru (pe)`_ … … 166 168 167 169 .. class:: at.forms.ATStateSelect 168 170 169 A ``Select`` widget that uses a list of Austrian states as its choices. 171 A ``Select`` widget that uses a list of Austrian states as its choices. 170 172 171 173 .. class:: at.forms.ATSocialSecurityNumberField 172 174 … … 406 408 407 409 A ``Select`` widget that uses a list of Japanese prefectures as its choices. 408 410 411 Malaysia (``my``) 412 ================= 413 414 .. class:: my.forms.MYIdentityCardNumberField 415 416 A form field that validates its input is a valid Malaysian Identity Card number. 417 (YYMMDD-BP-XXXX) 418 419 The regular expression used is sourced from: http://en.wikipedia.org/wiki/MyKad 420 421 Takes one extra optional argument: 422 423 .. attribute:: MYIdentityCardNumberField.check_bp_code 424 425 If ``True``, field will validate the BP digits is a valid BP (birth place) 426 code (see above Wikipedia link for more information). Default: ``True`` 427 428 .. class:: my.forms.MYPostCodeField 429 430 A form field that validates its input is a 5-digit Malaysian postcode. 431 432 .. class:: my.forms.MYPhoneNumberField 433 434 A form field that validates its input is a Malaysian phone number. 435 436 Accepts phone numbers in the format +6XXX-XXXXXXXX, with or without the 437 international country code prefix (+6) 438 439 .. class:: my.forms.MYStateSelect 440 441 A ``Select`` widget that uses a list of Malaysian states as its choices. 442 443 .. class:: my.models.IdentityCardNumberField 444 445 A model field that forms represent as a ``forms.MYIdentityCardNumberField`` 446 and validates its input is a Malaysian Identity Card number. 447 448 .. class:: my.models.PostCodeField 449 450 A model field that forms represent as a ``forms.MYPostCodeField`` and 451 validates its input is a Malaysian postcode. 452 453 .. class:: my.models.PhoneNumberField 454 455 A model field that forms represent as a ``forms.MYPhoneNumberField`` and 456 validates its input is a Malaysian phone number. 457 458 .. class:: my.models.StateField 459 460 A model field that forms represent as a ``forms.MYStateField`` and stores the 461 three-letter Malaysian state abbreviation in the database. 462 409 463 Mexico (``mx``) 410 464 =============== 411 465 … … 516 570 517 571 .. class:: ro.forms.ROIBANField 518 572 519 A form field that validates its input as a Romanian International Bank 573 A form field that validates its input as a Romanian International Bank 520 574 Account Number (IBAN). The valid format is ROXX-XXXX-XXXX-XXXX-XXXX-XXXX, 521 575 with or without hyphens. 522 576