Many-to-many field, save() method and the Django admin caveat

30 Oct · by Tim Kamanin · 1 min read

Surprise surprise!

When you save a model via admin forms it's not an atomic transaction. The main object gets saved first (to make sure it has a PK), then the M2M is cleared and the new values set to whatever came out of the form.

So if you are in the save() of the main object you are in a window of opportunity where the M2M hasn't been updated yet. In fact, if you try to do something to the M2M, the change will get wiped out by the clear(). More info can be found here: http://stackoverflow.com/a/1925784/469575.

So if you want to add many to many relationships on model save (for example, you want to add categories) in model save method like these:

def save(self, *args, **kwargs):
  category = Category.objects.get(pk=1)
  self.categories.add(category)

It won't work if you save model via admin, so to fix that you need to override save_related method on model admin form:

class ModelAdmin(admin.ModelAdmin):
  ...
  def save_related(self, request, form, formsets, change):
    super(ModelAdmin, self).save_related(request, form, formsets, change)
      category = Category.objects.get(pk=1)
      form.instance.categories.add(category)

And voila!

Want to get more 🔥 tips like this one?

Subscribe to get notified about new dev tutorials

Comments