Opened 9 years ago
Closed 9 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 , 9 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:2 by , 9 years ago
| Owner: | removed |
|---|---|
| Status: | assigned → new |
comment:3 by , 9 years ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:4 by , 9 years ago
| Resolution: | → needsinfo |
|---|---|
| Status: | assigned → closed |
comment:5 by , 9 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 , 9 years ago
| Resolution: | needsinfo |
|---|---|
| Status: | closed → new |
comment:7 by , 9 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 , 9 years ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |
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.
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
to
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.