These are my models in the models.py file.
class User(AbstractUser):
date_of_birth = models.DateField(blank=True, null=True)
bio = models.TextField(blank=True, null=True)
job = models.CharField(max_length=250, blank=True, null=True)
photo = models.ImageField(upload_to='account_images/',blank=True, null=True)
phone = models.CharField(max_length=11, blank=True, null=True)
followings = models.ManyToManyField('self', through='Contact', related_name='followers', symmetrical=False)
def get_absolute_url(self):
return reverse('social:user_detail', args=[self.username])
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_posts')
description = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
tags = TaggableManager(blank=True)
likes = models.ManyToManyField(User, related_name='liked_post', blank=True)
saved_by = models.ManyToManyField(User, related_name='saved_post', blank=True)
total_likes = models.PositiveIntegerField(default=0)
class Meta:
ordering = ['-created']
indexes = [
models.Index(fields=['-created'])
]
def __str__(self):
return self.author.username
def get_absolute_url(self):
return reverse('social:post_detail', args=[self.id])
class UserActivity(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_activity')
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='post_activity', blank=True, null=True)
action = models.CharField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user} {self.action} {self.post.author}' post"
I want to write a signal in which when a user likes a post, an object of the UserActivity model is created, and the value of the user field is set to the user who liked it. The post field should be set to the post that the user liked. And the action field should be set to 'likes'.
@receiver(post_save, sender=Post.likes.through)
def create_like_activity(sender, instance, **kwargs):
if instance.likes.exists():
UserActivity.objects.create(
user=instance.likes.last(),
post=instance.author,
action='likes'
)
I tried to achieve this through this approach, but it didn't work out. I'm relatively new to this and still at a beginner level in many concepts. I would appreciate your guidance.
You are listening to a wrong signal.
Instead you should be listening to m2m_changed signal.
Beware, this signal is fired/sent multiple times
"pre_add" Sent before one or more objects are added to the relation.
"post_add" Sent after one or more objects are added to the relation.
"pre_remove" Sent before one or more objects are removed from the
relation. "post_remove" Sent after one or more objects are removed
from the relation. "pre_clear" Sent before the relation is cleared.
"post_clear" Sent after the relation is cleared.
You can check when this signal is fired by checking action
.
Action:
action A string indicating the type of update that is done on the relation.
So, your code should look like this:
@receiver(m2m_changed, sender=Post.likes.through)
def create_like_activity(sender, instance, action, **kwargs):
if instance.likes.exists() and action == "post_add":
UserActivity.objects.create(
user=instance.likes.last(),
post=instance,
action='likes'
)