I am having an issue with the way Django class-based forms save a form. I am using a form.ModelForm
for one of my models which has some many-to-many relationships.
In the model's save method I check the value of some of these relationships to modify other attributes:
class MyModel(models.Model):
def save(self, *args, **kwargs):
if self.m2m_relationship.exists():
self.some_attribute = False
super(MyModel, self).save(*args, **kwargs)
Even if I populated some data in the m2m relationship in my form, I self.m2m_relationship
when saving the model and surprisingly it was an empty QuerySet
. I eventually found out the following:
The form.save()
method is called to save the form, it belongs to the BaseModelForm
class. Then this method returns save_instance
, a function in forms\models.py
. This function defines a local function save_m2m()
which saves many-to-many relationships in a form.
Here's the thing, check out the order save_instance
chooses when saving and instance and m2m:
instance.save()
save_m2m()
Obviously the issue is here. The instance's save
method is called first, that's why self.m2m_relationship
was an empty QuerySet
. It just doesn't exist yet.
What can I do about it? I can't just change the order in the save_instance
function because it is part of Django and I might break something else.
Daniel's answer gives the reason for this behaviour, you won't be able to fix it.
But there is the m2m_changed
signal that is sent whenever something changes about the m2m relationship, and maybe you can use that:
from django.db.models import signals
@signals.receiver(signals.m2m_changed, sender=MyModel.m2m_relationship.through)
def handle_m2m_changed(sender, instance, action, **kwargs):
if action == 'post_add':
# Do your check here
But note the docs say that instance "can be an instance of the sender, or of the class the ManyToManyField is related to".
I don't know how that works exactly, but you can try out which you get and then adapt the code.