Opened 7 years ago

Closed 7 years ago

#27433 closed Bug (invalid)

ModelForm with BooleanField can not save False/unchecked

Reported by: Christian Pedersen Owned by: Ingo Klöcker
Component: Forms Version: 1.10
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

Description

My model has this field

starred_only = models.BooleanField(default=False)

Overriden in the ModelForm

starred_only = forms.BooleanField(required=False)

Django 1.10 stopped saving the unchecked (False) value. 1.10.1 started doing it again, and from 1.10.2 it stopped.

This fixed it: https://github.com/django/django/pull/7068
And this broke it: https://github.com/django/django/pull/7217

I tried creating a custom widget:

class WorkingCheckboxInput(CheckboxInput):
    def value_omitted_from_data(self, data, files, name):
        return True

but value_omitted_from_data is never called.

The docs and/or minor release changelogs doesn't really document how to get the previous default behavior back.

Change History (8)

comment:1 by Patricia Sousa, 7 years ago

Owner: changed from nobody to Patricia Sousa
Status: newassigned

comment:2 by Patricia Sousa, 7 years ago

Owner: Patricia Sousa removed
Status: assignednew

comment:3 by Ingo Klöcker, 7 years ago

Owner: set to Ingo Klöcker
Status: newassigned

comment:4 by Ingo Klöcker, 7 years ago

Resolution: needsinfo
Status: assignedclosed

I could not reproduce the problem. The following test passes with Django 1.10.2.

class Test(TestCase):
    def test_27433(self):
        class Model(models.Model):
            starred_only = models.BooleanField(default=False)

        class Form(forms.ModelForm):
            starred_only = forms.BooleanField(required=False)

            class Meta:
                model = Model
                fields = ['starred_only']

        m = Model(starred_only=True)
        f = Form({}, instance=m)
        self.assertTrue(f.is_valid())
        self.assertFalse(m.starred_only)

The test fails if I change

                fields = ['starred_only']

to

                fields = []

but I think that's expected behavior.

See also https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#the-save-method (which I think you did already read).

Please provide a test case that demonstrates your bug.

comment:5 by Christian Pedersen, 7 years ago

This also happens in the Django Admin. I can not untick/mark false any records with a BooleanField(default=False)

The form is correctly marked as False, however the model is never updated from True -> False when calling save

comment:6 by Christian Pedersen, 7 years ago

Resolution: needsinfo
Status: closednew

comment:7 by Tim Graham, 7 years ago

I also cannot reproduce a problem here. Please more details about how to reproduce it, perhaps with a sample project. How I tried:

class Bool(models.Model):
    starred_only = models.BooleanField(default=False)

class BoolForm(forms.ModelForm):
    starred_only = forms.BooleanField(required=False)

    class Meta:
        fields = '__all__'

admin.site.register(Bool, form=BoolForm)

comment:8 by Christian Pedersen, 7 years ago

Resolution: invalid
Status: newclosed

I found the problem. It turns out django-cassandra-engine overrides the construct_instance method.

Change

        if (field_has_default and form.add_prefix(f.name) not in form.data and
                not getattr(form[f.name].field.widget,
                            'dont_use_model_field_default_for_empty_data',
                            False)):
            continue

to

        if (field_has_default and
                form[f.name].field.widget.value_omitted_from_data(form.data, form.files, form.add_prefix(f.name))):
            continue

That explains why it works in 1.10.1 only.

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