GuruRandapa
GuruRandapa

Reputation: 882

Django Signal Receiver Function not accepting sender

I am trying to create notification whenever a user likes a post. For that I am using django signals. I have previously used the sender arguement in the receiver decorator but don't why its not working this time. Here are my files.

#core.signals.py
@receiver(m2m_changed, sender=Post)
def likeNotification(sender,**kwargs):
    if kwargs['action'] == "post_add" and not kwargs['reverse']:
        post = kwargs['instance']
        to_user = post.user
        liked_by_users = kwargs['pk_set']
        like_notification = [Notification(
            post=post,
            user=to_user, sender=User.objects.get(id=user),
            text=f"{User.objects.get(id=user).profile.username} liked your post.", noti_type=3
        ) for user in liked_by_users]
        Notification.objects.bulk_create(like_notification)
#socialuser.models.py
class Post(Authorable, Creatable, Model):
    caption = TextField(max_length=350, null=True, blank=True)
    liked_by = ManyToManyField(
        "core.User", related_name="like_post", blank=True)

    objects = PostManager()

    def no_of_likes(self):
        return len(self.liked_by.all())

The receiver doesn't catch the signal when sender=Post, when I remove the sender it works as intended. On print the positional arguement sender of likeNotification function. This is what I get

<class 'socialuser.models.Post_liked_by'>

What am I doing wrong? Do I need to reference to the intermediate class Post_liked_by, if so how do I do that?

Upvotes: 1

Views: 772

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476614

You should specify the through model of the ManyToManyField of the model, so Post.liked_by.through, not Post: otherwise it is not clear on what ManyToManyField you are subscribing. We thus define the handler as:

#core/signals.py

@receiver(m2m_changed, sender=Post.liked_by.through)
def likeNotification(sender,**kwargs):
    # …

You can boost the efficiency to determine the number of likes with:

#socialuser/models.py

class Post(Authorable, Creatable, Model):
    # …

    def no_of_likes(self):
        return self.liked_by.count()

then it will determine the number of likes at the database side, and thus reduce the bandwidth from the database to the Django/Python application layer.

Upvotes: 2

Related Questions