tags:

views:

134

answers:

2

I am writing a Django app for use in a country where they use comma as decimal separator. I have a model that contains a django.db.models.DecimalField, and I use model forms. How can I make the resulting form field render using comma and accept comma back from the user?

Following the advice of jweyrich, I have upgraded my application from Django 1.1 to Django 1.2 and edited my settings.py to contain the following:

LANGUAGE_CODE = 'nb'
LANGUAGES = (
  ('nb', 'Norwegian'),
)
USE_I18N = True
USE_L10N = True
DECIMAL_SEPARATOR = ','
THOUSAND_SEPARATOR = ' '
MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
)

As far as I can see, this is all that the documentation calls for. It now works for forms if I set localization=True on the form field. It works in neither model forms nor the admin site, however.

I discovered a Django ticket and a resulting Django changeset from before the 1.2 release. If I am understanding them correctly, it used to be the case that the widgets used format localization automatically, but after this patch localization has to be turned on explicitly by giving the localization=True keyword parameter to the form field. Is there a way to make admin forms set localization=True on their fields?

+1  A: 

Right, this looks like an annoying breakage that I'm surprised no-one has reported. Because of the change you mention, localization has to be explicitly turned on for every field in your admin app or model form. The best way to do this would be to define a custom ModelForm for use both in the admin and in your app, and set the widgets dictionary to enable localization on each relevant field.

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'my_decimal_field': forms.TextInput(attrs={'localization': True}),
        }
Daniel Roseman
That only sets an attribute in the HTML, but you put me on the right track (a custom ModelForm turned out to be the way to go), so you get the bounty. Thanks! I'll post the working solution as a separate answer.
Vebjorn Ljosa
+1  A: 

Yes, localization does need to be turned in explicitly for every field. For a model form (including the ones used in the admin app), a convenient way to do this is to subclass ModelForm and turn on localization for each DecimalField:

import django

class LocalizedModelForm(django.forms.ModelForm):
    def __new__(cls, *args, **kwargs):
        new_class = super(LocalizedModelForm, cls).__new__(cls, *args, **kwargs)
        for field in new_class.base_fields.values():
            if isinstance(field, django.forms.DecimalField):
                field.localize = True
                field.widget.is_localized = True
        return new_class

Then you can define your custom ModelForm class and use it in the admin app:

class FooForm(LocalizedModelForm):

    class Meta:
        model = Foo


django.admin.site.register(Foo, form=FooForm)
Vebjorn Ljosa