Opened 14 months ago

Last modified 14 months ago

#34733 closed New feature

m2m_changed signal is unaware if .set() method is being called — at Initial Version

Reported by: Leif Kjos Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When a related_m2m_field.set() method is called, the m2m_changed signal is fired four times for action: pre_remove, post_remove, pre_add, and post_add (or pre_clear / post_clear).

This poses a problem if the signal is supposed to run validation on the final state of the model. For example, let's say I have a model called Customer with a many-to-many relation to SubscriptionPlan and I have a m2m_changed signal that is supposed to validate if their SubscriptionPlan is valid.

If I call subscription_plans.set([some_plans]), the many-to-many manager will first call subscription_plans.remove() then .add() inside an atomic transaction. If my signal validates on the first remove(), it could be in an invalid state, even though it won't be by the time the .add() completes.

To get around this, I had to create a custom ManyToManyField with a custom RelatedManager that set an instance variable on the model when the .set() method was called. I'd like to propose adding a feature to the RelatedManager or to the signals to make the m2m_changed signal aware of if the .set() method was called when running. This could be a private attribute on the instance or extra information passed to the signal receiver.

If this feature already exists or there's a decent workaround, let me know and i'll close the ticket! Otherwise, I have a patch in mind that I can raise a PR for and attach.

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top