class M(models.Model): f = models.CharField(max_length=255, default='default_value') class MF(forms.ModelForm): f = forms.CharField(required=False)
class Meta: model = M fields = ['f'] >>> mf = MF({}) >>> m = mf.save() >>> m.f
'' (Django 1.10+)
'default_value' (Django < 1.10)
For the case of fields that haven't been included in the form POST, I'd be surprised if they didn't end up with the model default.Personally I'd treat that as a regression, and revert to the older behavior.
A change in Django 1.10 inadvertently caused the following behavior change:class M(models.Model): f = models.CharField(max_length=255, default='default_value') class MF(forms.ModelForm): f = forms.CharField(required=False)
class Meta: model = M fields = ['f'] >>> mf = MF({}) >>> m = mf.save() >>> m.f
'' (Django 1.10+)
'default_value' (Django < 1.10)
On Django < 1.10, {'f': ''} as the form data (rather than empty form data) also results in a model instance with the model field default rather than an empty string. Claude and I agree that for this latter case, transforming an empty POST value to a model field default doesn't seem correct (that is, the new behavior seems better).
However, the desired behavior in the empty POST data case isn't so clear. For example, I could imagine an API call where it would be useful for the model to use the default if a user doesn't submit any data for that field. An issue with the idea that values not present in POST data fallback to their default is for HTML widgets like checkboxes. If a checkbox isn't checked, the key won't appear in POST data. In such a case, it's inappropriate for an unchecked checkbox to fallback to the model field's default if it's True. A draft patch to restore the Django < 1.10 behavior [1] special cases this with isinstance(form[f.name].field.widget, CheckboxInput) to fix some test failures but that hardly seems ideal.
Do you feel we should try to restore the Django < 1.10 behavior or keep the new behavior and document that model field defaults are used to populate initial blank forms but not to fill missing data from the form input?
Tobias McNulty
Chief Executive Officer
forms.BooleanField(required=False) feels like an odd combination to me in any case. One way we could potentially help users would be to error in that case unless an alternate widget is used (We could recommend select or whatever it is we use for NullBooleanField in this case)
We have the same issue in REST framework serializers FWIW. As with Django<1.10 we treat omission as omission, not blank. And yes, we have to special-case boolean omission.