diff --git a/docs/authors.rst b/docs/authors.rst index 4e41ef55..b58426da 100644 --- a/docs/authors.rst +++ b/docs/authors.rst @@ -130,3 +130,4 @@ Authors * Vladimir Nani * Xabi Bello * Abhineet Tamrakar +* Dishan Sachin diff --git a/docs/changelog.rst b/docs/changelog.rst index 642acdd8..73722de4 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,7 +6,8 @@ Changelog New flavors: -- None +- Sri Lanka LocalFlavor: Support for Sri Lanka added + (`gh-493 `_). New fields for existing flavors: diff --git a/docs/localflavor/lk.rst b/docs/localflavor/lk.rst new file mode 100644 index 00000000..648e7d4f --- /dev/null +++ b/docs/localflavor/lk.rst @@ -0,0 +1,19 @@ +Sri Lanka (``lk``) +============== + +Forms +----- + +.. automodule:: localflavor.lk.forms + :members: + +Models +------ + +.. automodule:: localflavor.lk.models + :members: + +Data +---- +.. autodata:: localflavor.lk.lk_provinces.PROVINCES +.. autodata:: localflavor.lk.lk_districts.DISTRICTS \ No newline at end of file diff --git a/localflavor/lk/__init__.py b/localflavor/lk/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/localflavor/lk/forms.py b/localflavor/lk/forms.py new file mode 100644 index 00000000..bbbf6139 --- /dev/null +++ b/localflavor/lk/forms.py @@ -0,0 +1,43 @@ +"""Sri Lanka specific Form helpers.""" + +from django.forms.fields import RegexField, Select +from django.utils.translation import gettext_lazy as _ + +from .lk_provinces import PROVINCES +from .lk_districts import DISTRICTS + + +class LKPostalCodeFormField(RegexField): + """ + A form field that accepts Sri Lanka postal code. + Format : XXXXX + + Postal codes: https://en.wikipedia.org/wiki/Postal_codes_in_Sri_Lanka + """ + + default_error_messages = { + 'invalid': _('Enter a postal code in format XXXXX'), + } + + def __init__(self, **kwargs): + super().__init__(r'^\d{5}$', **kwargs) + + +class LKProvinceSelect(Select): + """ + A Select widget with option to select a provinces from + list of all provinces of Sri Lanka. + """ + + def __init__(self, attrs=None): + super().__init__(attrs, choices=PROVINCES) + + +class LKDistrictSelect(Select): + """ + A Select widget with option to select a districts from + list of all districts of Sri Lanka. + """ + + def __init__(self, attrs=None): + super().__init__(attrs, choices=DISTRICTS) diff --git a/localflavor/lk/lk_districts.py b/localflavor/lk/lk_districts.py new file mode 100644 index 00000000..53939d23 --- /dev/null +++ b/localflavor/lk/lk_districts.py @@ -0,0 +1,82 @@ +""" +List of Districts of Sri Lanka. + +Source: https://en.wikipedia.org/wiki/Districts_of_Sri_Lanka + +Sri Lanka districts list choices are in this format: + + ('name_of_districts',_('Name of districts')), + +eg. + ('name_of_district', _('Name of district')), +""" + +from django.utils.translation import gettext_lazy as _ + +# list of districts in Central +CENTRAL_DISTRICTS = [ + ('kandy', _('Kandy')), + ('matale', _('Matale')), + ('nuwara_eliya', _('Nuwara Eliya')), +] + +# list of districts in North Central +NORTH_CENTRAL_DISTRICTS = [ + ('anuradhapura', _('Anuradhapura')), + ('polonnaruwa', _('Polonnaruwa')), +] + +# list of districts in Northern +NORTHERN_DISTRICTS = [ + ('jaffna', _('Jaffna')), + ('kilinochchi', _('Kilinochchi')), + ('mannar', _('Mannar')), + ('vavuniya', _('Vavuniya')), + ('mullativu', _('Mullativu')), + ('alambil', _('Alambil')), +] + +# list of districts in Eastern +EASTERN_DISTRICTS = [ + ('ampara', _('Ampara')), + ('batticaloa', _('Batticaloa')), + ('trincomalee', _('Trincomalee')), +] + +# list of districts in North Western +NORTH_WESTERN_DISTRICTS = [ + ('kurunagala', _('Kurunagala')), + ('puttalam', _('Puttalam')), +] + +# list of districts in Southern +SOUTHERN_DISTRICTS = [ + ('galle', _('Galle')), + ('hambanthota', _('Hambanthota')), + ('mathara', _('Mathara')), +] + +# list of districts in Uva +UVA_DISTRICTS = [ + ('badulla', _('Badulla')), + ('monaragala', _('Monaragala')), +] + +# list of districts in Sabaragamuwa +SABARAGAMUWA_DISTRICTS = [ + ('kegalle', _('Kegalle')), + ('rathnapura', _('Rathnapura')), +] + +# list of districts in Western +WESTERN_DISTRICTS = [ + ('colombo', _('Colombo')), + ('gampaha', _('Gampaha')), + ('kaluthara', _('Kaluthara')), +] + +# Combining all the district lists from different provinces into a single list +DISTRICTS = CENTRAL_DISTRICTS + NORTH_CENTRAL_DISTRICTS + NORTHERN_DISTRICTS + EASTERN_DISTRICTS + NORTH_WESTERN_DISTRICTS + SOUTHERN_DISTRICTS + UVA_DISTRICTS + SABARAGAMUWA_DISTRICTS + WESTERN_DISTRICTS + +# Alphabetically sorting the list of all districts based on their names (first element of each tuple) +DISTRICTS.sort(key=lambda district: district[0]) \ No newline at end of file diff --git a/localflavor/lk/lk_provinces.py b/localflavor/lk/lk_provinces.py new file mode 100644 index 00000000..28f79e22 --- /dev/null +++ b/localflavor/lk/lk_provinces.py @@ -0,0 +1,26 @@ +""" +List of Provinces of Sri Lanka. + +Source: https://en.wikipedia.org/wiki/Provinces_of_Sri_Lanka + +Sri Lanka province list choices are in this format: + + ('name_of_province',_('Name of province')), + +eg. + ('central', _('Central')), +""" + +from django.utils.translation import gettext_lazy as _ + +PROVINCES = [ + ('central', _('Central')), + ('north_central', _('North Central')), + ('northern', _('Northern')), + ('eastern', _('Eastern')), + ('north_western', _('North Western')), + ('southern', _('Southern')), + ('uva', _('Uva')), + ('sabaragamuwa', _('Sabaragamuwa')), + ('western', _('Western')), +] \ No newline at end of file diff --git a/localflavor/lk/models.py b/localflavor/lk/models.py new file mode 100644 index 00000000..586f61ce --- /dev/null +++ b/localflavor/lk/models.py @@ -0,0 +1,79 @@ +"""Sri Lanka specific Model fields""" + +import re + +from django.core.validators import RegexValidator +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from .forms import LKPostalCodeFormField +from .lk_districts import DISTRICTS +from .lk_provinces import PROVINCES + + +class LKPostalCodeValidator(RegexValidator): + """ + A validator for Sri Lanka Postal Codes. + """ + default_error_messages = { + 'invalid': _('Enter a postal code in format XXXXX'), + } + + def __init__(self, *args, **kwargs): + super().__init__(re.compile(r'^\d{5}$'), *args, **kwargs) + + +class LKPostalCodeField(models.CharField): + """ + A model field that accepts Sri Lanka postal codes. + Format: XXXXX + Source: https://en.wikipedia.org/wiki/Postal_codes_in_Sri_Lanka + .. versionadded:: 4.0 + """ + description = _("Postal Code") + + def __init__(self, *args, **kwargs): + kwargs['max_length'] = 5 + super().__init__(*args, **kwargs) + self.validators.append(LKPostalCodeValidator()) + + def formfield(self, **kwargs): + defaults = {'form_class': LKPostalCodeFormField} + defaults.update(kwargs) + return super().formfield(**defaults) + + +class LKDistrictField(models.CharField): + """ + A model field that provides an option to select + a district from the list of all Sri Lanka districts. + .. versionadded:: 4.0 + """ + + def __init__(self, *args, **kwargs): + kwargs['choices'] = DISTRICTS + kwargs['max_length'] = 15 + super().__init__(*args, **kwargs) + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + del kwargs['choices'] + return name, path, args, kwargs + + +class LKProvinceField(models.CharField): + """ + A model field that provides an option to select + a province from the list of all Sri Lanka provinces. + .. versionadded:: 4.0 + """ + + def __init__(self, *args, **kwargs): + kwargs['choices'] = PROVINCES + kwargs['max_length'] = 15 + super().__init__(*args, **kwargs) + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + del kwargs['choices'] + return name, path, args, kwargs diff --git a/tests/settings.py b/tests/settings.py index 8cce7c1c..fcd29acc 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -21,6 +21,7 @@ 'tests.test_gh', 'tests.test_np', 'tests.test_ca', + 'tests.test_lk', 'tests.test_generic', ] diff --git a/tests/test_lk/__init__.py b/tests/test_lk/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_lk/models.py b/tests/test_lk/models.py new file mode 100644 index 00000000..34117ab9 --- /dev/null +++ b/tests/test_lk/models.py @@ -0,0 +1,8 @@ +from django.db import models + +from localflavor.lk.models import (LKDistrictField, LKProvinceField) + + +class LKPlace(models.Model): + district = LKDistrictField(blank=True) + province = LKProvinceField(blank=True) diff --git a/tests/test_lk/selectfields_html.py b/tests/test_lk/selectfields_html.py new file mode 100644 index 00000000..0266f806 --- /dev/null +++ b/tests/test_lk/selectfields_html.py @@ -0,0 +1,46 @@ +"""Option for all select box fields""" + +districts_select = """ + +""" + +provinces_select = """ + +""" diff --git a/tests/test_lk/tests.py b/tests/test_lk/tests.py new file mode 100644 index 00000000..37a32ef9 --- /dev/null +++ b/tests/test_lk/tests.py @@ -0,0 +1,50 @@ +from django.test import TransactionTestCase +from localflavor.lk.forms import LKDistrictSelect, LKPostalCodeFormField, LKProvinceSelect + +from .selectfields_html import districts_select, provinces_select +from .models import LKPlace + + +class SriLanakDetailsTests(TransactionTestCase): + """ + This Test class tests all the selectbox + fields and Postal Code Fields. + """ + + def test_LKDistrictSelect(self): + field = LKDistrictSelect() + self.assertHTMLEqual(field.render('district', 'kandy'), districts_select) + + def test_LKProvinceSelect(self): + field = LKProvinceSelect() + self.assertHTMLEqual(field.render('province', 'central'), provinces_select) + + def test_LKPostalCodeFieldTest(self): + error_format = ['Enter a postal code in format XXXXX'] + valid = { + '12345': '12345', + '00000': '00000', + '11111': '11111' + } + invalid = { + '12345_123': error_format, + '1234-123': error_format, + '-232': error_format, + 'abc_den': error_format, + '2345-': error_format, + } + self.assertFieldOutput(LKPostalCodeFormField, valid, invalid) + + def test_LKDistrictField(self): + place = LKPlace() + place.district = 'kandy' + place.clean_fields() + place.save() + self.assertEqual(place.get_district_display(), 'Kandy') + + def test_LKProvinceField(self): + place = LKPlace() + place.province = 'central' + place.clean_fields() + place.save() + self.assertEqual(place.get_province_display(), 'Central')