Homunculus Reticulli
Homunculus Reticulli

Reputation: 68426

Sending and receiving signals in django models

I am using django 2.0.8 and Python 3.5. I want to be able to send and receive custom signals when an object is saved to the database.

I have followed the Django documentation on listening to signals and also the core signals bundled with Django - however, I am unable to get my example to work.

This is what I have so far:

myapp/models.py

from django.db import models
import django.dispatch

my_signal = django.dispatch.Signal(providing_args=["name"])

class Foo(models.Model):
    name = models.CharField(max_length=16)

def save(self, *args, **kwargs):
    try:
        # Call the "real" save() method.
        super().save(*args, **kwargs)  

        # Fire off signal         
        my_signal.send(sender=self.__class__, name=self.name)

    except Exception as e:
        print ('Exception:', e)
        #pass

myapp/signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Foo


@receiver(post_save, sender=Foo)
def foo_handler(sender, **kwargs):
    print('Foo Signal Recieved!')
    print(kwargs)

myapp/app.py

class MyappConfig(AppConfig):
    name = 'myapp'
    label = 'myapp'

    def ready(self):
        import myapp.signals

Sample usage

from myapp.models import Foo

foo = Foo(name='Homer Simpson')
foo.save() # Object is saved, but event is not fired!

Can anyone explain why the signal is not being fired?

Upvotes: 8

Views: 5223

Answers (3)

firelynx
firelynx

Reputation: 32214

You are reinventing the wheel, but only putting it on one side of the cart, so to speak.

the post_save signal is always sent on save, so defining your own signal is overkill. I know you got the argument there, but the receiver has the sender argument already, which is the saved object, so you can just do sender.name and you got the value you need.

Apart from that, you have a syntax error, your custom save function for your model is not indented. I don't know if this is a formatting error in your question or if that is how it looks in your code. Either way, should work if you just drop your custom signal.

Model

from django.db import models
import django.dispatch


class Foo(models.Model):
    name = models.CharField(max_length=16)

Signals

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Foo


@receiver(post_save, sender=Foo)
def foo_handler(sender, **kwargs):
    print(sender.name)

App

class MyappConfig(AppConfig):
    name = 'myapp'
    label = 'myapp'

    def ready(self):
        import myapp.signals

Sample

from myapp.models import Foo

foo = Foo(name='Homer Simpson')
foo.save()

Upvotes: 1

newlife
newlife

Reputation: 778

It seems you need two features supplied by Django. signal and contenttypes.

So read the doc first

The model Activity is related to contenttypes,seems you miss object_id Field, which indicate which model instance is being crud.

For every crud action, An Activity instance is being created.This part is just the code written in signal.py

signal: signal have to connect each concrete model. Fortunately,See the source code of decorator receiver.

We have a signal list [post_save,post_delete] and a model list (FoodooChile, FooBarChile) to connect .

In post_save,argument created indicate the action is create or update.

At last, Usually we import the signal file in urls.py, maybe not the best practice.


It is also related to your settings.py. use 'myapp.apps.MyappConfig' replace myapp in settings.py,or define default_app_config = 'myapp.apps.MyappConfig' in myapp/__init__.py. The link above in comments describe this in detail

Upvotes: 8

Ghariani Mohamed
Ghariani Mohamed

Reputation: 166

  1. In the myapp.signals you have a receiver that handels the post_save signal (@receiver(post_save, sender=Foo)) it doesn't connect to your signal.
  2. Make sure you are using your app config in the __init__.py of you application default_app_config = 'myapp.apps.MyappConfig'
  3. To connect to the signal you created try this in your signals.py file:

    @receiver(my_signal)
        def my_handler(name, **kwargs):
            print(name)
    

Upvotes: 1

Related Questions