Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#22324 closed Uncategorized (invalid)

form.has_change() is always True if BooleanField(default=True)

Reported by: osamak Owned by: nobody
Component: Forms Version: 1.6
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


In any ModelForm, if the model has a BooleanField with True as the default value, any instance of the ModelForm will automatically have form.has_changed() set to True. This doesn't apply if the default value is False.

Take this model example:

class Test(models.Model):
    test_field = models.BooleanField(default=True)

And take this ModelForm example:

class TestForm(ModelForm):
    class Meta:
        model = Test
        fields = ['test_field']

In the previous example:

>> form = TestForm()
>> form.has_changed()

Change History (6)

comment:1 Changed 4 years ago by Claude Paroz

Resolution: invalid
Status: newclosed

Sure, but I don't see what's wrong with that. default=True means the initial value of test_field in the form will be True. Then when you instantiate a form without parameters, it's like you passed False as the new field value, which explains why has_changed returns True.

comment:2 Changed 4 years ago by Claude Paroz

Component: contrib.formtoolsForms

comment:3 Changed 4 years ago by osamak

But why no parameters indicate False when the default value is True?

Anyway, even after passing parameters, here is the result:

>> initial_test = Test(test_field=True)
>> form = TestForm(instance=initial_test)
>> form.has_changed()

comment:4 Changed 4 years ago by Claude Paroz

When you create an instance of a form without anything in the data parameter, the form is unbound and all values will be considered empty, or False for boolean values. Generally, has_changed is queried after the form has received some data, for example:

>>> initial_test = Test(test_field=True)
>>> form = TestForm(data={'test_field': 'on'}, instance=initial_test)
>>> form.has_changed()

comment:5 Changed 4 years ago by osamak

Thanks for the explanation! One last thing: could you explain why we need to pass 'on' in the first place when the default value is already True? This seems to violate the DRY principle.

comment:6 Changed 4 years ago by Claude Paroz

The data provided to a form is most of the time coming from a web form POSTed to the view. In forms, BooleanField is generally represented by a checkbox, and many browsers do send the "on" value when submitting checked checkboxes. But I could have replaced 'on' by True, and the result would be the same.

If you need more information, please use the support channels.

Note: See TracTickets for help on using tickets.
Back to Top