Why Django model signals are not working?
I am trying to create activity streams of users from their status.
models:
class Status(models.Model):
body = models.TextField(max_length=200)
image = models.ImageField(blank=True, null=True, upload_to=get_upload_file_name)
privacy = models.CharField(max_length=1,choices=PRIVACY, default='F')
pub_date = models.DateTimeField(auto_now_add=True, auto_now=False)
user = models.ForeignKey(User)
class Activity(models.Model):
actor = models.ForeignKey(User)
action = models.CharField(max_length=100)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
pub_date = models.DateTimeField(auto_now_add=True, auto_now=False)
However, although I create a new status, it does not create a new activity from the post_save
signal.
signals:
from django.contrib.contenttypes.models import ContentType
from django.db.models.signals import post_save
from status.models import Status
from models import Activity
def create_activity_item(sender, instance, signal, *args, **kwargs):
if kwargs.get('created', True):
ctype = ContentType.objects.get_for_model(instance)
if ctype.name == 'Status':
action = ' shared '
activity = Activity.objects.get_or_create(
actor = instance.user,
action = action,
content_type = ctype,
object_id = instance.id,
pub_date = instance.pubdate
)
post_save.connect(create_activity_item, sender=Status)
What am I doing wrong? Please help me solve this problem. I will be very much grateful. Thank you.
Update:
However doing like this creates the activity:
@receiver(post_save, sender=Status)
def create(sender, instance, **kwargs):
if kwargs.get('created',True):
ctype = ContentType.objects.get_for_model(instance)
activity = Activity.objects.get_or_create(
actor = instance.user,
action = ' shared ',
content_type = ctype,
object_id = instance.id,
pub_date = instance.pub_date
)
Why doesn't the above works then?
Seems like your post_save.connect
is not executed. You should import signals
somewhere. For django 1.7 it is recommended to do this in the app's config ready() function. Read the "Where should this code live?" side note in the docs.
For example if your app is called activity
:
activity/__init__.py
default_app_config = 'activity.apps.ActivityAppConfig'
activity/apps.py
from django.apps import AppConfig
class ActivityAppConfig(AppConfig):
name = 'activity'
def ready(self):
import activity.signals
And don't forget to add dispatch_uid to your connect()
call:
post_save.connect(create_activity_item, sender=Status,
dispatch_uid="create_activity_item")
UPDATE: name
attribute of ContentType
is always in lower case. So you should change the if
statement to:
if ctype.name == 'status':
let's say your apps name is blog
, in the settings.py file of your project ensure to register the blog
app in the INSTALLED_APP variable of your main project's settings.py file as blog.apps.BlogConfig
and not just blog
. That worked for me.
Without touching apps.py this worked for me.
class MyModel(models.Model):
""" MyModel fields go """
body = models.TextField(max_length=200)
pub_date = models.DateTimeField(auto_now_add=True, auto_now=False)
def post_save_actions(sender, instance, created, **kwargs):
if created:
pass
# post save actions if new instance is created,
# do something with `instance` or another models
# be careful about circular imports. \m/
and the signals hook,
post_save.connect(post_save_user_actions, sender=MyModel)
if you write everything in signals.py
correctly but not working, then check these steps... (suppose in an app named AppName)
-
in
__init__.py
, put the linedefault_app_config = 'AppName.apps.AppnameConfig'
-
in
apps.py
file, put the blockfrom django.apps import AppConfig
class AppnameConfig(AppConfig): name = 'AppName'
def ready(self): import AppName.signals