Search code examples
pythondjangodjango-signals

How to send a django signal from other signal


TL;DR:
I need a way to trigger a custom signal after the post_save signal, automatically, is there any way of doing it?


I'm currently developing a library for django that requires a lot of comes and goes with the post_save signal in django and I was wondering if it's possible to trigger another signal after the post_save so I could implement my own and not intervene the post_save in case a project that uses the library needs to do it.

So far I know that signals are expected to receive a class as a sender argument, and if I trigger manually the signal from the post_save I would be doing nothing (I'd still be intervening it). Is there any workaround for this? Am I missing something in the docs?


Solution

  • Although this may be possible by calling a signal manually from inside another signal like this:

    post_save.send(MyModel, instance=a_mymodel_instance)
    

    There are easier ways to do something like that:

    Let us assume that you follow the file organization that I use in this answer: Django Create and Save Many instances of model when another object are created


    Suggestion 1:

    • Let us assume that your first post_save does something to MyModel1 and another post_save signal does something to MyModel2 after some processing on the instance that triggered the first signal.
    • post_save is always send at the end of a save() method.
    • Organize your signals as follows:

      @receiver(post_save, sender=MyModel1)
      def mymodel1_signal (sender, instance, **kwargs):
          Do stuff on MyModel1 instance...
          Do also stuff on MyModel2 and then call MyModel2.save()
      
      
      @receiver(post_save, sender=MyModel2)
      def mymodel2_signal (sender, instance, **kwargs):
          Do stuff on MyModel2 instance...
      

      This way the mymodel2_signal signal will get triggered after the call to MyModel2.save() from mymodel1_signal.


    Suggestion 2:

    • Use a mix of signals to achieve the correct "timing".
    • Let us assume that you want to start a process on MyModel2 before a MyModel1 get's saved
    • Use a pre_save and a post_save signal:

      @receiver(pre_save, sender=MyModel1)
      def mymodel1_signal (sender, instance, **kwargs):
          Do stuff on MyModel1 instance...
          Do also stuff on MyModel2 and then call MyModel2.save()
      
      
      @receiver(post_save, sender=MyModel2)
      def mymodel2_signal (sender, instance, **kwargs):
          Do stuff on MyModel2 instance...
      

    Suggestion 3:

    Use a MyModel2 method directly inside a MyModel1 post_save signal.