﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
16612	Localized form fields cause Form.has_changed() to always return True.	rviotti@…	nobody	"Localized form fields are causing Form.has_changed() to always return True.

I've created a minimal project to test this. Here is the relevant part of the settings.py file.

{{{
TIME_ZONE = 'America/Sao_Paulo'
USE_THOUSAND_SEPARATOR = True
LANGUAGE_CODE = 'pt-br'
USE_I18N = True
USE_L10N = True
}}}

The test model.

{{{
from django.db import models

class TestModel(models.Model):
    numeric_field = models.DecimalField(max_digits=10, decimal_places=2)

    @models.permalink
    def get_absolute_url(self):
        return ('edit', [str(self.pk)])
}}}

The test form.

{{{
from django import forms

from app.models import TestModel

class TestForm(forms.ModelForm):
    class Meta:
        model = TestModel

    numeric_field = forms.DecimalField(localize=True)
}}}

The test view.

{{{
from django.shortcuts import get_object_or_404, render, redirect

from app.forms import TestForm
from app.models import TestModel

def edit_instance(request, instance_id):
    inst = get_object_or_404(TestModel, pk=instance_id)

    if request.method == 'POST':
        form = TestForm(request.POST, instance=inst)

        if form.is_valid():
            inst = form.save()

            print 'FORM CHANGED?', form.has_changed()

            return redirect(inst)

    else:
        form = TestForm(instance=inst)

    return render(request, 'testmodel.html', {'form': form})
}}}

And template code.

{{{
<html>
    <head>
        <title>Bugreports</title>
    </head>

    <body>
        <form action="""" method=""post"">
            {% csrf_token %}

            {{ form.as_p }}

            <input type=""submit"" />
        </form>
    </body>
</html>
}}}

The print statement above emits True whenever I hit the submit button, regardless of changes on the numeric field value. This is because Form._has_changed_data is comparing raw localized POST data with initial data, coming from the model, both converted to Unicode. For example, the request POST data is ""1,23"" and the initial data obtained from the model field is Decimal('1.23'). The test ""unicode(u'1,23') == unicode(Decimal('1.23'))"" fails.

The following !ModelForm specialization compares initial data with cleaned data, which, IMHO, is the adequate way to do field change detection.

{{{
class ModelFormSubclass(forms.ModelForm):
    def _get_changed_data(self):
        if self._changed_data is None:
            self._changed_data = []

            for name, field in self.fields.items():
                data_value = self.cleaned_data[name]
                initial_value = self.initial.get(name, field.initial)

                # Replace instances with their primary key values.
                if hasattr(data_value, 'pk'):
                    data_value = data_value.pk

                if data_value != initial_value:
                    self._changed_data.append(name)

        return self._changed_data

    changed_data = property(_get_changed_data)
}}}

The overriden method fixed my specific problem. I'm posting it primarily for consideration of the proposed concept, and secondly, as a preliminary solution to the aforementioned issue.
"	Bug	closed	Forms	dev	Normal	fixed			Ready for checkin	1	0	0	0	0	0
