7

I have a Django model with 2 ManyToMany fields. I want to process the data from the model each time it has been saved.

The post_save signal is sent before it saves the ManyToMany relations, so I can't use that one. Then you have the m2m_changed signal, but since I have 2 ManyToMany fields I cannot be sure on which ManyToMany field I should put the signal.

Isn't there a signal that is triggered after all the ManyToMany fields have been saved?

gitaarik
  • 42,736
  • 12
  • 98
  • 105
  • Try this, found via a google: http://techblog.ironfroggy.com/2011/02/django-how-to-hook-in-after-multiple.html - might give you some pointers – Henrik Andersson Apr 12 '13 at 12:54
  • Thanks, however the solution on the link you posted only works if you only use the Django admin. I need support when the model has been saved outside of the Django admin too. – gitaarik Apr 12 '13 at 13:04
  • http://stackoverflow.com/questions/1221878/why-does-django-post-save-signal-give-me-pre-save-data – catherine Apr 12 '13 at 13:38
  • @catherine the ticket they're talking about in the other SO question is what resulted in the m2m_changed signal – gitaarik Apr 12 '13 at 13:50

1 Answers1

3

I feel like the only option is to process the data after every m2m_change, since there doesn't appear to be an event or signal that maps to "all related data on this model has finished saving."

If this is high cost, you could handle the processing asynchronously. When I encountered a similar situation, I added a boolean field to the model to handle state as it related to processing (e.g., MyModel.needs_processing) and a separate asynchronous task queue (Celery, in my case) would sweep through every minute and handle the processing/state resetting.

In your case, if m2m_changed and needs_processing is False, you could set needs_processing to True and save the model, marking it for processing by your task queue. Then, even when the second m2m_changed fired for the other m2m field, it wouldn't incur duplicate processing costs.

gitaarik
  • 42,736
  • 12
  • 98
  • 105
Jeremy Bowers
  • 196
  • 1
  • 7