I want automatically update an external application about a change in a model. The problem is that the data is in a many2many relation between events <-> users. I tried to use the "m2m_changed" signal.
@receiver(m2m_changed, sender=models.Event.organisers.through)
def event_changed(sender, instance, action, *args, **kwargs):
if "post" in action:
# hey api here is the new list of organisers of this
The problem with this is that if i make a single change where i remove one user and add another then this code is called twice! That's no good and i can't just ignore one type of operation in case only that operation is called. I have thought pushing instances to stacks and ignoring dups but that seems messy. Is there a way i can make my own signal that only fires once?
Django m2m_changed
indicates change on ManyToMany model. If has 4 actions
So if you're just adding a user, this m2m_changed method would be triggered 2 times, for pre_add
and post_add
respectively.
You can specify at which action you want to call API. This could be done as:
@receiver(m2m_changed, sender=models.Event.organisers.through)
def event_changed(sender, instance, action, *args, **kwargs):
if kwargs.get('action') == 'pre_add': # Or whatever action you want
# Call your API here
Reference Django Docs: https://docs.djangoproject.com/en/2.2/ref/signals/#m2m-changed
Django m2m_changed
indicates change on ManyToMany model. If has 4 actions
So if you're just adding a user, this m2m_changed method would be triggered 2 times, for pre_add
and post_add
respectively.
You can specify at which action you want to call API. This could be done as:
@receiver(m2m_changed, sender=models.Event.organisers.through)
def event_changed(sender, instance, action, *args, **kwargs):
if kwargs.get('action') == 'pre_add': # Or whatever action you want
# Call your API here
Reference Django Docs: https://docs.djangoproject.com/en/2.2/ref/signals/#m2m-changed
There doesn't relay seem to be a good answer to this question so here is some useful workarounds that are better than what i was imagined in the first pace.
Instead of combining signals instead add the primary keys of the instances to a set to ignore duplicate signals:
updated = set()
@receiver(m2m_changed, sender=models.Event.organisers.through)
def event_changed(sender, instance, action, *args, **kwargs):
if "post" in action:
updated.add(instance.pk)
def send_updates():
for Event in updated: # Iteration AKA for each element
#update code here
While this requires some sort of scheduled task to run send_updates() it avoids the chance of spamming if there are many consecutive changes to the event.
Ignore signals altogether add last modified to the model. Then run a query to get all events between now and when the send_updates() was last called. Store the last called somewhere to disk/database to avoid having to resend everything on restart.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With