Django antipatterns 〉antipattern 〉Using commit=False when altering the instance in a ModelForm Fork me on GitHub

Often one sees a pattern where one aims to update an instance wrapped in a ModelForm before creating a record in the database. A programmer often writes:

form = MyFormClass(request.POST, request.FILES)
if form.is_valid():
object = form.save(commit=False)
object.some_attribute = some_value
object.save()

# Why is it a problem?

Because commit=False does not only result in not creating a record at the database. It also has for example impact on many-to-many fields in the form.

When you thus specify commit=False, the ManyToManyFields of the model that are also present in the form, are not stored in the database either, since at that moment, no primary key for the object exists yet.

One can of course implement the logic themselves, but the idea of a ModelForm is to remove as much boilerplate code as possible.

# What can be done to resolve the problem?

You alter the instance wrapped in the form before saving the form, so:

form = MyFormClass(request.POST, request.FILES)
if form.is_valid():
form.instance.some_attribute = some_value
form.save()

That way the form can still handle other tasks it needs to carry out in the save method, and furthermore it is a more "clean" implementation.