I have added a notification where every time a user submits a Like button to a post, the owner of the liked post receives a notification.
I have set Value options for each Like button to be Like or Unlike I have restricted the notification to be sent only if the Value of the like clicked is Like only.
So, now in the Like Model I have added signal and a condition that if the Like.value== Like the signal activates but for some reason it is sent twice only when a new post is created and a new user clicks like for the very first time, afterwards if he unike and likes again it is sent once.
My question is:
Why is the signal duplicated everytime a new user clicks the Like button? How to fix it?
Here is the post models.py:
class Post(models.Model):
title = models.CharField(max_length=100, unique=True)
likes = models.ManyToManyField(User, related_name='liked', blank=True)
here is the Like model.py:
LIKE_CHOICES = (
('Like', 'Like'),
('Unlike', 'Unlike')
)
class Like(models.Model):
# To know Who liked
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
value = models.CharField(choices=LIKE_CHOICES, default='Like', max_length=8)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.post}-{self.user}-{self.value}"
def user_liked_post(sender, instance, *args, **kwargs):
like = instance
if like.value=='Like':
post = like.post
sender = like.user
notify = Notification(post=post, sender=sender, user=post.author, notification_type=1)
notify.save()
def user_unlike_post(sender, instance, *args, **kwargs):
like = instance
post = like.post
sender = like.user
notify = Notification.objects.filter(post=post, sender=sender, user=post.author, notification_type=1)
notify.delete()
# Likes
post_save.connect(Like.user_liked_post, sender=Like)
post_delete.connect(Like.user_unlike_post, sender=Like)
Here is the views.py:
def ShowNotifications(request):
user=request.user
notifications= Notification.objects.filter(user=user).order_by('-date')
template= loader.get_template('notifications/notifications.html')
context= {
'notifications':notifications
}
return HttpResponse(template.render(context, request))
You can try this way:
from django.db import models
from django.db.models.signals import post_save, post_delete
from django.contrib.auth.models import User
from django.dispatch import receiver
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=100, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='post_author')
def __str__(self):
return self.title
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.post.title}@_{self.user}"
@receiver(post_save, sender=Like)
def user_liked_post(sender, instance, created, *args, **kwargs):
try:
if created:
notify = Notification(
post=instance.post,
sender=instance.user,
user=instance.post.author,
notification_type=1
)
notify.save()
except Exception as e:
print('Error sending liked notification!')
print(e)
@receiver(post_delete, sender=Like)
def user_unlike_post(sender, instance, *args, **kwargs):
try:
notify = Notification.objects.filter(
post=instance.post,
sender=instance.user,
)
notify.delete()
except Exception as e:
print('Error deleting liked notification!')
print(e)
Since you are deleting the liked record then the status of the record will never be unlike
and the updated
field is also not going to update.
So remove the update and value fields from Like
model.
And in below line you are fetching the author
from Post
model but there is no author field in Post
model.
notify = Notification(post=post, sender=sender, user=post.author, notification_type=1)