I have set a Notification system for my Django project whenever a user likes or comments on a post the Author receives a notification about this activity.
I have read about the Signals in django: https://docs.djangoproject.com/en/3.1/topics/signals/#listening-to-signals
In the Post Model, I have added a num_likes
which reflects the number of likes the post has received.
I am trying to add an option so that the Author of the Post can receive a Notification when the num_likes
reaches a certain number. In my example, it is the First Like.
So, here is what I have tried but nothing happened.
Here is the models.py
class Post(models.Model):
title = models.CharField(max_length=100, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author')
num_likes = models.IntegerField(default=0, verbose_name='No. of Likes')
likes = models.ManyToManyField(User, related_name='liked', blank=True)
def __str__(self):
return self.title
#---------------------------My trial------------------------------------------
def like_progress(sender, instance, *args, **kwargs):
post = instance
if post.num_likes == 1:
notify = Notification(post=post, user=post.author, notification_type=3)
notify.save()
# num_likes
post_save.connect(Post.like_progress, sender=Post)
#---------------------------My trial------------------------------------------
Here are the notifications model.py
class Notification(models.Model):
NOTIFICATION_TYPES=((1,'Like'),(2,'Comment'),(3,'Admin'))
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, related_name="noti_post", blank=True, null=True)
sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name="noti_from_user")
user = models.ForeignKey(User, on_delete=models.CASCADE,related_name="noti_to_user")
notification_type= models.IntegerField(choices=NOTIFICATION_TYPES)
text_preview= models.CharField(max_length=90,blank=True)
date=models.DateTimeField(auto_now=True)
is_seen=models.BooleanField(default=False)
def __str__(self):
return self.notification_type
here are the notifications app views.py
def ShowNotifications(request, *args, **kwargs):
user=request.user
notifications= Notification.objects.filter(user=user).order_by('-date')
Notification.objects.filter(user=user, is_seen=False).update(is_seen=True)
template= loader.get_template('notifications/notifications.html')
context = {
'notifications': notifications,
}
return HttpResponse(template.render(context, request))
here is the url.py
app_name = 'notifications'
urlpatterns = [
path('', ShowNotifications, name='show-notifications'),
here is the template:
<!-- Admin Notification -->
{% if notification.notification_type == 3 %}
Your First Like in this post
{% endif %}
<!-- Admin Notification -->
So to summarize:
I have a perfectly working Notification system I am just trying to add to it an option to notify the Author
of a Post that he received a first like for example. What am I doing wrong in the above and how can I get this feature to work?
If there is anything vague or more information required please ask
You don't receive the notification because of these two lines in your view:
notifications= Notification.objects.filter(user=user).order_by('-date')
Notification.objects.filter(user=user, is_seen=False).update(is_seen=True)
Let me explain what happens in those lines.
is_seen
as True in DB.is_seen=False
in the DB as you already updated them in step 2 to is_seen=True
. So, the loop in the template that renders the notifications shows nothing as it could not find any unseen notifications in the DB.To mitigate this, convert the notifications in step 1 to list, so that the query will be executed immediately. In this way, you are passing an actual list of objects to your template and not a lazy queryset.
This solves your problem:
notifications= list(Notification.objects.filter(user=user).order_by('-date'))
Converting it to list forces Django to immediately execute the query and return the objects
Define like_progress
in a new file, signals.py, in the same directory as .models.Post
instead of in the model. This will help avoid side effects.
In practice, signal handlers are usually defined in a signals submodule of the application they relate to.
Register the signal handler in the appConfig for the app which contains the Post
model, I called the app "blog", so the module path is blog.apps.BlogConfig
and add that module path to INSTALLED_APPS
, instead of just the app name.
From the docs:
Signal receivers are connected in the ready() method of your application configuration class.
And check out more information on the ready method .
Your apps.py file in the blog app (whereever Post
model lives) should look like so:
from django.apps import AppConfig
from django.db.models.signals import post_save
class BlogConfig(AppConfig):
name = 'blog'
def ready(self):
from .models import Post
from .signals import like_progress
post_save.connect(like_progress, sender=Post)
Note that the imports need to happen in the ready
method. There is also an option to specify the model import as a string.
Remember to also specify another user as a sender when you create the Notification. As in:
notify = Notification(post=post, user=post.author, sender=liker, notification_type=3)
And you might want to check out the docs on avoiding duplicate registration of signal handlers .
It's all in the docs you linked to, but it helped a lot to see what happened in the shell ( python manage.py shell
). At first it failed silently, but once the signal handler was moved into signals.py and registered in appConfig it started to show some results.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.