From 958c0fe0eee7e539137ad1999c1a42ea775766db Mon Sep 17 00:00:00 2001 From: Simon Fransson Date: Wed, 10 Sep 2014 14:53:08 +0200 Subject: [PATCH 1/8] Added dictionaries for numerical county codes and full county names. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I have added the following dictionaries and functions to se_counties: NUMERICAL_COUNTY_CODES contains the numerical two-digit couty codes which has more or less replaced the alphabetical codes nowadays. Also, these numerical codes is always the leading digits in the codes for municipailites and smaller subdivisions, which can be beneficial. FULL_COUNTY_NAMES contains the full names of each county. The current labels given in SE_COUNTIES is good when it is obvioius to the user that he/she is selecting a county, but they are not identical to the full county name. Also, in Swedish the county names differ somewhat, e.g. "Skåne län" as opposed to the more generic "Stockholms län" (ending with genitive case s), which the Swedish i18n should honor. numerical_county_code() and full_county_name() are simply accessor methods for the above dictionaries, returning the corresponding values given a alphabetical county code. For backwards compatibility I have chosen to keep both the alphabetical codes and the shortened names (lacking the "county"-part) in the original SE_COUNTIES list, although I guess one could argue numerical codes and full names would be a better option. --- localflavor/se/se_counties.py | 71 +++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/localflavor/se/se_counties.py b/localflavor/se/se_counties.py index b6e1c5ed9..b4a8dd8cf 100644 --- a/localflavor/se/se_counties.py +++ b/localflavor/se/se_counties.py @@ -28,3 +28,74 @@ ('Y', _('Västernorrland')), ('Z', _('Jämtland')), ) + +#: A dictionary of numerical county codes, with alphabetical codes +#: as keys and the more modern numerical codes as values. +#: +#: Values taken from https://sv.wikipedia.org/wiki/Sveriges_län, +#: and code system described at https://sv.wikipedia.org/wiki/Länskod +#: and http://www.scb.se/sv_/Hitta-statistik/Regional-statistik-och-kartor/Regionala-indelningar/Lan-och-kommuner/Lan-och-kommuner-i-kodnummerordning/ + +NUMERICAL_COUNTY_CODES = { + 'AB': '01', + 'AC': '24', + 'BD': '25', + 'C': '03', + 'D': '04', + 'E': '05', + 'F': '06', + 'G': '07', + 'H': '08', + 'I': '09', + 'K': '10', + 'M': '12', + 'N': '13', + 'O': '14', + 'S': '17', + 'T': '18', + 'U': '19', + 'W': '20', + 'X': '21', + 'Y': '22', + 'Z': '23', +} + +#: A dictionary of full county names, as these are not as +#: somewhat in Swedish, e.g. "Skåne län" as opposed to +#: the more generic "Stockholms län" (ending with genitive case s) + +FULL_COUNTY_NAMES = { + 'AB': _('Stockholm County'), + 'AC': _('Västerbotten County'), + 'BD': _('Norrbotten County'), + 'C': _('Uppsala County'), + 'D': _('Södermanland County'), + 'E': _('Östergötland County'), + 'F': _('Jönköping County'), + 'G': _('Kronoberg County'), + 'H': _('Kalmar County'), + 'I': _('Gotland County'), + 'K': _('Blekinge County'), + 'M': _('Skåne County'), + 'N': _('Halland County'), + 'O': _('Västra Götaland County'), + 'S': _('Värmland County'), + 'T': _('Örebro County'), + 'U': _('Västmanland County'), + 'W': _('Dalarna County'), + 'X': _('Gävleborg County'), + 'Y': _('Västernorrland County'), + 'Z': _('Jämtland County'), +} + + +def numerical_county_code(county_code): + """Returns a numerical county code for the supplied alphabetical county code.""" + + return NUMERICAL_COUNTY_CODES.get(county_code, None) + + +def full_county_name(county_code): + """Returns a full county name for the supplied alphabetical county code.""" + + return FULL_COUNTY_NAMES.get(county_code, None) From b222b240843cd2db83e8759bd758ef1b1b229aba Mon Sep 17 00:00:00 2001 From: Simon Fransson Date: Wed, 10 Sep 2014 15:00:35 +0200 Subject: [PATCH 2/8] Added @county_decorator() which adds a few accessor methods to models The decorator adds get_FIELDNAME_numerical_code() and get_FIELDNAME_full_name() methods to django models for all FIELDNAME values supplied in the field_names tuple. Ideally this can be used on all model fields that uses COUNTY_CHOICES for the choices argument. @county_decorator(field_names('field',)) class MyClass: field = models.CharField(choices=se_counties=COUNTY_CHOICES) --- localflavor/se/decorators.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 localflavor/se/decorators.py diff --git a/localflavor/se/decorators.py b/localflavor/se/decorators.py new file mode 100644 index 000000000..16da96c9c --- /dev/null +++ b/localflavor/se/decorators.py @@ -0,0 +1,24 @@ +from django.utils.decorators import method_decorator +from .se_counties import numerical_county_code, full_county_name + +def county_decorator(field_names=()): + """Decorator that adds get_FIELDNAME_numerical_code() and get_FIELDNAME_full_name() methods + to django models for all FIELDNAME values supplied in the field_names tuple. Ideally + this can be used on all model fields that uses COUNTY_CHOICES for the choices argument. + + @county_decorator(field_names('field',)) + class MyClass: + field = models.CharField(choices=se_counties=COUNTY_CHOICES) + """ + + def decorate(cls): + for field_name in field_names: + + _get_numerical_code = lambda self: numerical_county_code(getattr(self, field_name)) + _get_full_name = lambda self: full_county_name(getattr(self, field_name)) + + setattr(cls, "get_" + field_name + "_numerical_code", _get_numerical_code) + setattr(cls, "get_" + field_name + "_full_name", _get_full_name) + + return cls + return decorate From a15abc3da83d291fc5edd8b31218cee07a06d080 Mon Sep 17 00:00:00 2001 From: Simon Fransson Date: Thu, 11 Sep 2014 11:37:41 +0200 Subject: [PATCH 3/8] Removed unused dependency. --- localflavor/se/decorators.py | 1 - 1 file changed, 1 deletion(-) diff --git a/localflavor/se/decorators.py b/localflavor/se/decorators.py index 16da96c9c..9e0d8f5f8 100644 --- a/localflavor/se/decorators.py +++ b/localflavor/se/decorators.py @@ -1,4 +1,3 @@ -from django.utils.decorators import method_decorator from .se_counties import numerical_county_code, full_county_name def county_decorator(field_names=()): From 703a53f6f4798d07ff86aa734095db4a8457c56d Mon Sep 17 00:00:00 2001 From: Simon Fransson Date: Thu, 11 Sep 2014 11:40:07 +0200 Subject: [PATCH 4/8] Formatting --- localflavor/se/decorators.py | 1 + 1 file changed, 1 insertion(+) diff --git a/localflavor/se/decorators.py b/localflavor/se/decorators.py index 9e0d8f5f8..ab893a436 100644 --- a/localflavor/se/decorators.py +++ b/localflavor/se/decorators.py @@ -1,5 +1,6 @@ from .se_counties import numerical_county_code, full_county_name + def county_decorator(field_names=()): """Decorator that adds get_FIELDNAME_numerical_code() and get_FIELDNAME_full_name() methods to django models for all FIELDNAME values supplied in the field_names tuple. Ideally From c4c446209d898ee1048b42224105348b553a6b39 Mon Sep 17 00:00:00 2001 From: Simon Fransson Date: Fri, 21 Nov 2014 12:12:14 +0100 Subject: [PATCH 5/8] Removed class decorator and added SECountyField to handle model accessors for full county name and numerical codes. Also renamed `FULL_COUNTY_NAMES` and `NUMERICAL_COUNTY_CODES` in `se_counties.py` into `NUMERICAL_COUNTY_CODE_CHOICES` and `FULL_COUNTY_NAME_CHOICES` respectively, as well as converted them both to tuple lists rather than dicts in order for them to be supplied as the `chocies` argument for the field. --- localflavor/se/decorators.py | 24 -------- localflavor/se/models.py | 63 +++++++++++++++++++++ localflavor/se/se_counties.py | 100 +++++++++++++++------------------- 3 files changed, 107 insertions(+), 80 deletions(-) delete mode 100644 localflavor/se/decorators.py create mode 100644 localflavor/se/models.py diff --git a/localflavor/se/decorators.py b/localflavor/se/decorators.py deleted file mode 100644 index ab893a436..000000000 --- a/localflavor/se/decorators.py +++ /dev/null @@ -1,24 +0,0 @@ -from .se_counties import numerical_county_code, full_county_name - - -def county_decorator(field_names=()): - """Decorator that adds get_FIELDNAME_numerical_code() and get_FIELDNAME_full_name() methods - to django models for all FIELDNAME values supplied in the field_names tuple. Ideally - this can be used on all model fields that uses COUNTY_CHOICES for the choices argument. - - @county_decorator(field_names('field',)) - class MyClass: - field = models.CharField(choices=se_counties=COUNTY_CHOICES) - """ - - def decorate(cls): - for field_name in field_names: - - _get_numerical_code = lambda self: numerical_county_code(getattr(self, field_name)) - _get_full_name = lambda self: full_county_name(getattr(self, field_name)) - - setattr(cls, "get_" + field_name + "_numerical_code", _get_numerical_code) - setattr(cls, "get_" + field_name + "_full_name", _get_full_name) - - return cls - return decorate diff --git a/localflavor/se/models.py b/localflavor/se/models.py new file mode 100644 index 000000000..636938893 --- /dev/null +++ b/localflavor/se/models.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from .se_counties import COUNTY_CHOICES, NUMERICAL_COUNTY_CODE_CHOICES, FULL_COUNTY_NAME_CHOICES + + +class SECountyField(models.CharField): + """ + A standard `CharField` with `choices` defaulting to `localflavor.se.se_counties.COUNTY_CHOICES`. + + As the Swedish counties can be named in at least two ways (e.g. "Stockholm" vs. "Stockholm County"), + and there has historically been at least two numeric systems used for counties, this field adds the + following accessors to let you access all of this data: + + * `get_county_numerical_code()` - Numiercal code (01-25) + * `get_county_full_name()` - Full Name (e.g. Stockholm County) + * `get_county_short_name()`- Short name (e.g. Stockholm) + + Example: + + .. code-block:: python + + from django.db import models + from localflavor.se.models import SECountyField + from .se_counties import COUNTY_CHOICES, NUMERICAL_COUNTY_CODE_CHOICES, FULL_COUNTY_NAME_CHOICES + + class MyModel(models.Model): + county = SECountyField() + + obj = MyModel(county='AB') + + obj.get_county_numerical_code() # '01' + obj.get_county_full_name() # 'Stockholm County' + obj.get_county_short_name() # 'Stockholm' + obj.get_county_display() # 'Stockholm' + obj.county # 'AB' + + https://sv.wikipedia.org/wiki/Sveriges_län + https://en.wikipedia.org/wiki/Counties_of_Sweden + """ + description = _('A Swedish County') + + def __init__(self, *args, **kwargs): + + if not 'choices' in kwargs: + kwargs['choices'] = COUNTY_CHOICES + + if not 'max_length' in kwargs: + kwargs['max_length'] = 2 + + super(SECountyField, self).__init__(*args, **kwargs) + + def contribute_to_class(self, cls, name): + if not cls._meta.abstract: + _get_numerical_code = lambda self: dict(NUMERICAL_COUNTY_CODE_CHOICES).get(getattr(self, name), None) + _get_full_name = lambda self: dict(FULL_COUNTY_NAME_CHOICES).get(getattr(self, name), None) + _get_short_name = lambda self: dict(COUNTY_CHOICES).get(getattr(self, name), None) + + cls.add_to_class("get_" + name + "_numerical_code", _get_numerical_code) + cls.add_to_class("get_" + name + "_full_name", _get_full_name) + cls.add_to_class("get_" + name + "_short_name", _get_short_name) + + super(SECountyField, self).contribute_to_class(cls, name) diff --git a/localflavor/se/se_counties.py b/localflavor/se/se_counties.py index b4a8dd8cf..ce4493479 100644 --- a/localflavor/se/se_counties.py +++ b/localflavor/se/se_counties.py @@ -36,66 +36,54 @@ #: and code system described at https://sv.wikipedia.org/wiki/Länskod #: and http://www.scb.se/sv_/Hitta-statistik/Regional-statistik-och-kartor/Regionala-indelningar/Lan-och-kommuner/Lan-och-kommuner-i-kodnummerordning/ -NUMERICAL_COUNTY_CODES = { - 'AB': '01', - 'AC': '24', - 'BD': '25', - 'C': '03', - 'D': '04', - 'E': '05', - 'F': '06', - 'G': '07', - 'H': '08', - 'I': '09', - 'K': '10', - 'M': '12', - 'N': '13', - 'O': '14', - 'S': '17', - 'T': '18', - 'U': '19', - 'W': '20', - 'X': '21', - 'Y': '22', - 'Z': '23', +NUMERICAL_COUNTY_CODE_CHOICES = { + ('AB', '01',), + ('AC', '24',), + ('BD', '25',), + ('C', '03',), + ('D', '04',), + ('E', '05',), + ('F', '06',), + ('G', '07',), + ('H', '08',), + ('I', '09',), + ('K', '10',), + ('M', '12',), + ('N', '13',), + ('O', '14',), + ('S', '17',), + ('T', '18',), + ('U', '19',), + ('W', '20',), + ('X', '21',), + ('Y', '22',), + ('Z', '23',), } #: A dictionary of full county names, as these are not as #: somewhat in Swedish, e.g. "Skåne län" as opposed to #: the more generic "Stockholms län" (ending with genitive case s) -FULL_COUNTY_NAMES = { - 'AB': _('Stockholm County'), - 'AC': _('Västerbotten County'), - 'BD': _('Norrbotten County'), - 'C': _('Uppsala County'), - 'D': _('Södermanland County'), - 'E': _('Östergötland County'), - 'F': _('Jönköping County'), - 'G': _('Kronoberg County'), - 'H': _('Kalmar County'), - 'I': _('Gotland County'), - 'K': _('Blekinge County'), - 'M': _('Skåne County'), - 'N': _('Halland County'), - 'O': _('Västra Götaland County'), - 'S': _('Värmland County'), - 'T': _('Örebro County'), - 'U': _('Västmanland County'), - 'W': _('Dalarna County'), - 'X': _('Gävleborg County'), - 'Y': _('Västernorrland County'), - 'Z': _('Jämtland County'), +FULL_COUNTY_NAME_CHOICES = { + ('AB', _('Stockholm County'),), + ('AC', _('Västerbotten County'),), + ('BD', _('Norrbotten County'),), + ('C', _('Uppsala County'),), + ('D', _('Södermanland County'),), + ('E', _('Östergötland County'),), + ('F', _('Jönköping County'),), + ('G', _('Kronoberg County'),), + ('H', _('Kalmar County'),), + ('I', _('Gotland County'),), + ('K', _('Blekinge County'),), + ('M', _('Skåne County'),), + ('N', _('Halland County'),), + ('O', _('Västra Götaland County'),), + ('S', _('Värmland County'),), + ('T', _('Örebro County'),), + ('U', _('Västmanland County'),), + ('W', _('Dalarna County'),), + ('X', _('Gävleborg County'),), + ('Y', _('Västernorrland County'),), + ('Z', _('Jämtland County'),), } - - -def numerical_county_code(county_code): - """Returns a numerical county code for the supplied alphabetical county code.""" - - return NUMERICAL_COUNTY_CODES.get(county_code, None) - - -def full_county_name(county_code): - """Returns a full county name for the supplied alphabetical county code.""" - - return FULL_COUNTY_NAMES.get(county_code, None) From 2bda725243e6e680a56c6febd5f2f379751a3512 Mon Sep 17 00:00:00 2001 From: Simon Fransson Date: Fri, 21 Nov 2014 12:17:54 +0100 Subject: [PATCH 6/8] Syntax conformance. --- localflavor/se/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/localflavor/se/models.py b/localflavor/se/models.py index 636938893..2b732e646 100644 --- a/localflavor/se/models.py +++ b/localflavor/se/models.py @@ -42,10 +42,10 @@ class MyModel(models.Model): def __init__(self, *args, **kwargs): - if not 'choices' in kwargs: + if 'choices' not in kwargs: kwargs['choices'] = COUNTY_CHOICES - if not 'max_length' in kwargs: + if 'max_length' not in kwargs: kwargs['max_length'] = 2 super(SECountyField, self).__init__(*args, **kwargs) From ca6bbb7aeb9d79fc08001619aee62f9aa6cf8951 Mon Sep 17 00:00:00 2001 From: Simon Fransson Date: Fri, 21 Nov 2014 12:22:07 +0100 Subject: [PATCH 7/8] Fixed bad dict => tuple conversion. --- localflavor/se/se_counties.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/localflavor/se/se_counties.py b/localflavor/se/se_counties.py index ce4493479..7fa346b73 100644 --- a/localflavor/se/se_counties.py +++ b/localflavor/se/se_counties.py @@ -36,7 +36,7 @@ #: and code system described at https://sv.wikipedia.org/wiki/Länskod #: and http://www.scb.se/sv_/Hitta-statistik/Regional-statistik-och-kartor/Regionala-indelningar/Lan-och-kommuner/Lan-och-kommuner-i-kodnummerordning/ -NUMERICAL_COUNTY_CODE_CHOICES = { +NUMERICAL_COUNTY_CODE_CHOICES = ( ('AB', '01',), ('AC', '24',), ('BD', '25',), @@ -58,13 +58,13 @@ ('X', '21',), ('Y', '22',), ('Z', '23',), -} +) #: A dictionary of full county names, as these are not as #: somewhat in Swedish, e.g. "Skåne län" as opposed to #: the more generic "Stockholms län" (ending with genitive case s) -FULL_COUNTY_NAME_CHOICES = { +FULL_COUNTY_NAME_CHOICES = ( ('AB', _('Stockholm County'),), ('AC', _('Västerbotten County'),), ('BD', _('Norrbotten County'),), @@ -86,4 +86,4 @@ ('X', _('Gävleborg County'),), ('Y', _('Västernorrland County'),), ('Z', _('Jämtland County'),), -} +) From a7dff89d9c9c7ebce34ef7e277f825eca3ea967f Mon Sep 17 00:00:00 2001 From: Simon Fransson Date: Fri, 21 Nov 2014 17:54:12 +0100 Subject: [PATCH 8/8] Better defaults for SECountyField. --- localflavor/se/models.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/localflavor/se/models.py b/localflavor/se/models.py index 2b732e646..b1d517571 100644 --- a/localflavor/se/models.py +++ b/localflavor/se/models.py @@ -42,13 +42,13 @@ class MyModel(models.Model): def __init__(self, *args, **kwargs): - if 'choices' not in kwargs: - kwargs['choices'] = COUNTY_CHOICES + defaults = { + 'max_length': 2, + 'choices': COUNTY_CHOICES, + } + defaults.update(kwargs) - if 'max_length' not in kwargs: - kwargs['max_length'] = 2 - - super(SECountyField, self).__init__(*args, **kwargs) + super(SECountyField, self).__init__(*args, **defaults) def contribute_to_class(self, cls, name): if not cls._meta.abstract: