ModelForm with field subset saving all fields

89 views
Skip to first unread message

Cristina Botez

unread,
Jul 20, 2017, 9:53:32 AM7/20/17
to Django users
I'm using a view that combines 2 forms (which were split in order to facilitate reuse and to separate concerns). The model instance I am sending to both is the same, so when one form sets the new values on the instance, the other can see them. The problem is that when the first form is saved, the changes made through the second form are also committed. Functionally, this is not a problem, but I also generate some historical records and expect to have 2 different historical records generated after these modifications - or in any case, I expect the fields to be grouped based on this separation. (Background: the records are generated by a post_save signal receiver).

My expectation was that updating an instance via a form will only update the set of fields specified in ModelForm.Meta.fields, not all the fields of the instance. It would also make a lot more sense in case the model has TextFields not included in the form being saved.
I know I could just call super().save(commit=False) and then just save the instance using the update_fields parameter, but I think this functionality should come out of the box.

My question is: Are there any considerations that I'm not aware of to prevent saving the instance with the update_fields set to ModelForm.Meta.fields in the base implementation of ModelForm?

Tim Graham

unread,
Jul 29, 2017, 8:44:55 PM7/29/17
to Django users
It might be worth considering. Here's a quick patch:

diff --git a/django/forms/models.py b/django/forms/models.py
index ffa8982..bd5d108 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -454,7 +454,8 @@ class BaseModelForm(BaseForm):
             )
         if commit:
             # If committing, save the instance and the m2m data immediately.
-            self.instance.save()
+            kwargs = {} if self.instance._state.adding else {'update_fields': self._meta.fields}
+            self.instance.save(**kwargs)
             self._save_m2m()
         else:
             # If not committing, add a method to the form to allow deferred

There are a few test failures with Django's test suite that might be fixable. The change could be subtly backwards incompatible in some edge cases.
Reply all
Reply to author
Forward
0 new messages