Django Signals - trigger when model changed

1,711 views
Skip to first unread message

Omar Helal

unread,
Oct 5, 2019, 2:33:30 PM10/5/19
to django...@googlegroups.com
Hi all,

I came across this ticket in stack overflow to try to find a solution for the issue of calling a signal only when a particular field on a model was updated.


I didn't want to use any third party libraries (especially one that had migrations on the DB) and wanted to use the built in signals provided by Django.

My initial solution is to:

1) Create the function I want to trigger when the particular field has changed (in the questioner's case the music field on the Album instance)

    def do_this_when_album_music_changed(sender, **kwargs):
        // do something
        print("I'm only going to be called if the field has changed")

2) Create the custom signal I want to send when the particular field changes

    album_music_changed = Signal(providing_args=[])

3) Create a pre_save signal receiver that will check whether or not the field has changed and "connect" the custom signal to the receiver, otherwise "disconnect" it

    @receiver(signal=signal=models.signals.pre_save, sender=Album)
    def album_pre_save(sender, instance, **kwargs):
        old_album = sender.objects.get(pk=instance.pk)
        if not old_album.music == instance.music:
            album_music_changed.connect(do_this_when_album_music_changed, sender=Album)
        else:
            album_music_changed.disconnect(do_this_when_album_music_changed, sender=Album)

4) Finally add a post_save signal that will actually send the trigger to call the custom signal and hence the function you want to run

    @receiver(signal=signal=models.signals.post_save, sender=Album)
    def album_post_save(sender, instance, **kwargs):
        album_music_changed.send(sender=sender)

In my case, I need to have the function run after post_save of the instance so this was the best thing I could come up with, if anyone has a better solution that would be awesome if you could share it.

Of course if you don't need the triggered function to run post_save and you are happy to run it pre_save you can just call the .send() inside the first "if" block and not have to worry about the post_save receiver

Omar
Reply all
Reply to author
Forward
0 new messages