I feel that the only way is to process the data after each m2m_change , as it does not seem to be an event or signal that compares โall associated data of this model with storageโ.
If this is a high cost, you can process the processing asynchronously. When I faced a similar situation, I added a model logical field to handle the processing-related state (e.g. MyModel.needs_processing ), and a separate asynchronous task queue (Celery, in my case) will go through every minute and process the processing reset / condition.
In your case, if m2m_changed and needs_processing is False , you can set needs_processing to True and save the model by marking it for processing according to your task queue. Then, even when the second m2m_changed triggered for another m2m field, this will not lead to duplication of processing costs.
Jeremy bowers
source share