How do I sort choices by their localized label?

1,303 views
Skip to first unread message

Salvatore Iovene

unread,
Feb 11, 2012, 8:12:11 AM2/11/12
to django...@googlegroups.com
Hi,
I have the following custom field:

from django.utils.translation import ugettext_lazy as _

COUNTRIES = (
    ('GB', _('United Kingdom')),
    ('AF', _('Afghanistan')),
    ('AX', _('Aland Islands')),
    ('AL', _('Albania')),
    ('DZ', _('Algeria')),
    .
    .
    .
)

class CountryField(models.CharField):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('max_length', 2)
        kwargs.setdefault('choices', COUNTRIES)
        super(CountryField, self).__init__(*args, **kwargs)

    def get_internal_type(self):
        return "CharField"


That field ends up in an HTML <select>, and I'd like the countries to be sorted by their label in all locales. I have tried to replace this code:

kwargs.setdefault('choices', COUNTRIES)

with this:

kwargs.setdefault('choices', sorted(COUNTRIES, key=lambda x: x[1]))

but that's sorting the list only by the original English names, whatever the locale.

I can't switch to ugettext instead of the _lazy version, because this is a Field so it won't work at all.

Do you have any suggestion on how to get my list of countries properly sorted in all locales?

Thank you!
Salvatore Iovene.

Kevin Harvey

unread,
Feb 11, 2012, 8:23:14 AM2/11/12
to django...@googlegroups.com
Have you tried sorting them at the template level? A filter like dictsort might do the trick https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#dictsort

ajohnston

unread,
Feb 11, 2012, 11:59:39 AM2/11/12
to Django users
I think this should work:

>>> COUNTRIES = (
... ('GB', _('United Kingdom')),
... ('AF', _('Afghanistan')),
... ('AX', _('Aland Islands')),
... ('AL', _('Albania')),
... ('DZ', _('Algeria')),)

>>> sorted(COUNTRIES, key=lambda COUNTRIES: COUNTRIES[1])
[('AF', 'Afghanistan'), ('AX', 'Aland Islands'), ('AL', 'Albania'),
('DZ', 'Algeria'), ('GB', 'United Kingdom')]

ajohnston

unread,
Feb 11, 2012, 12:32:09 PM2/11/12
to Django users
Sorry I just realized that even though that sorts them correctly, it
doesn't solve your problem.

Have you tried setting the choices in your form, like:

class SomeFormUsingCountryField(forms.Form):
def __init__(self, *args, **kwargs):
super(SomeFormUsingCountryField, self).__init__(*args,
**kwargs)
self.fields['country_field'].choices = sorted(COUNTRIES,
key=lambda c: c[1])

Salvatore Iovene

unread,
Feb 11, 2012, 2:20:29 PM2/11/12
to django...@googlegroups.com
On Saturday, February 11, 2012 7:32:09 PM UTC+2, ajohnston wrote:
Have you tried setting the choices in your form, like:

class SomeFormUsingCountryField(forms.Form):
    def __init__(self, *args, **kwargs):
        super(SomeFormUsingCountryField, self).__init__(*args,
**kwargs)
        self.fields['country_field'].choices = sorted(COUNTRIES,
key=lambda c: c[1])

Funny, that fixes it. Thanks!

It's a layer violation, so I have to do it for each form that uses my field, but it works.

Salvatore. 

ajohnston

unread,
Feb 11, 2012, 3:52:48 PM2/11/12
to Django users
> class CountryField(models.CharField):
>     def __init__(self, *args, **kwargs):
>         kwargs.setdefault('max_length', 2)
>         kwargs.setdefault('choices', COUNTRIES)
>         super(CountryField, self).__init__(*args, **kwargs)

Btw, the reason this doesn't work is because setdefault doesn't work
as you think it does. See [1] for an example.

For the 'layer violation', you might try:

class CountryField(models.CharField):
def __init__(self, *args, **kwargs):
super(CountryField, self).__init__(*args, **kwargs)
self.choices = sorted(COUNTRIES, key=lambda c: c[1])
...

I haven't tried this but it might work.
Cheers


[1]http://www.saltycrane.com/blog/2010/02/python-setdefault-example/
Reply all
Reply to author
Forward
0 new messages