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

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!

Comments

Required for comment verification



Omar

Thanks for this. Saved a lot of headaches. :)

Reply · 11 months, 1 week ago
James

Also wanted to thank you for taking the time to write up that tip - very helpful!

Reply · 2 years, 1 month ago
Jim

Thanks for that tip. I was beating my head against the desk until I found your post. Saved me a whole lot of time.

Reply · 2 years, 8 months ago