With your diligent writing, more and more people will read your articles, and their comments will be scattered across many articles. As a blogger, readers must read all their comments; When readers leave you messages, they expect a response.
How do I present unread messages to the right users? The user can’t go to the boundless article to find it, that’s too stupid. Adding notification functions to comments is a popular solution: such as notification on wechat moments, notification on Sina Weibo, and “little red dots” on various social media platforms.
This article will build a simple notification system based on Django-Notifications.
Send a notification
The previous steps are already familiar.
First install Django-notifications:
(env) > pip install django-notifications-hq
Copy the code
Register app:
my_blog/settings.py
...
INSTALLED_APPS = [
...
'notifications'. ] .Copy the code
Install path in root route:
my_blog/urls.py
...
import notifications.urls
urlpatterns = [
...
path('inbox/notifications/', include(notifications.urls, namespace='notifications')),... ] .Copy the code
Notice that the notifications. Urls here are not strings as before, to ensure that the module is installed in the correct namespace.
Data migration:
(env) > python manage.py migrate
Copy the code
Your app is installed.
Then you can send notifications anywhere in the project! Like this:
from notifications.signals import notify
notify.send(actor, recipient, verb, target, action_object)
Copy the code
The meaning of the parameters:
actor
: Object to which notifications are sentrecipient
: Indicates the object that receives the notificationverb
: phrasal verbtarget
: Object linked to the action * (optional) *action_object
: (Optional) Object to perform the notification
A bit tricky, for example: Actor posts an action_object comment on you in a Django target.
Since we want to send notifications when a user posts a comment, we modify the comment view:
comments/views.py
...
from notifications.signals import notify
from django.contrib.auth.models import User
...
def post_comment(...).:.Create a new reply
if comment_form.is_valid():
...
# Existing code, secondary reply
if parent_comment_id:
...
# add code to send notifications to other users
if not parent_comment.user.is_superuser:
notify.send(
request.user,
recipient=parent_comment.user,
verb='Got back to you',
target=article,
action_object=new_comment,
)
return HttpResponse('200 OK')
new_comment.save()
# add code to send notification to administrator
if not request.user.is_superuser:
notify.send(
request.user,
recipient=User.objects.filter(is_superuser=1),
verb='Got back to you',
target=article,
action_object=new_comment,
)
return redirect(article)
...
Copy the code
2019/6/4 Fix this code. The old code incorrectly placed notify sent to the administrator before new_comment.save(), resulting in NULL action_object storage.
Add two notify statements in two if statements:
- The first one
notify
: Users can comment on each other, so notifications need to be sent.if
Statement to prevent administrators from receiving duplicate notifications. - The second
notify
: All comments are notified to the administrator (i.e. the blogger), except for the administrator himself.
The rest of the code doesn’t change, just be careful where you put it. You can try sending a few comments and then open SQLiteStudio to see how the data changes in the NotificationS_Notification table.
With only 4 lines of valid code, we’re done creating and sending notifications! You’re starting to see the benefits of using third-party libraries. This is standing on the shoulders of giants.
Little red dot
The logic to create notifications in the background is already written, but if it doesn’t show up in the front end, it doesn’t work.
The most popular front-end notification display is the “little red dot”, which has become so popular that many applications don’t even need it. Another form is the message badge **, which is a red box with a count of message entries. Both methods are used in the blog page.
In the choice of location, the header is a good fit because it is displayed everywhere on the blog, fitting the positioning of the notification itself.
So modify header.html:
templates/header.html
<! Importing the notifications template tag -->
{% load notifications_tags %}
{% notifications_unread as unread_count %}
...
<! -- Existing code, user dropdown box -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" .>
<! -- New code, little red dot -->
{% if unread_count %}
<svg viewBox="0 0 8 8"
width="8px"
height="8px">
<circle cx="4"
cy="4"
r="4"
fill="#ff6b6b"
></circle>
</svg>
{% endif %}
{{ user.username }}
</a>
<! -- Existing code, link in drop down box -->
<div class="dropdown-menu" .>
<! -- Add code, notification count -->
<a class="dropdown-item" href="#">Notification {% if unread_count %}<span class="badge badge-danger">{{ unread_count }}</span>
{% endif %}
</a>.<a .>Log out</a>
</div>
</li>.Copy the code
Django-notifications comes with a simple template tag that calls important notification related objects in the foreground template and can be used at the top. For example, unread_count is the count of unread notifications for the current user.
Bootstrap comes with a badge, but it doesn’t have a red dot (at least I didn’t find one), so I had to draw it in SVG, which wasn’t hard.
SVG is a label for drawing vector graphics, which will not be expanded here. If you are interested, please search for related articles.
Make a few random comments and refresh the page to have a look:
It worked well. But the href of the link is empty, so we’ll deal with that.
Unread and read
Since it is a notice, it can certainly be divided into ** “unread” and “read” two types. In due course, unread notifications need to be converted to read. Now let’s develop features to deal with it centrally.
Notifications are a standalone feature that could be used anywhere in the future, and it seems inappropriate to put them in a review app.
So create a new app:
(env) > python manage.py startapp notice
Copy the code
Registration:
my_blog/settings.py
...
INSTALLED_APPS = [
...
'notice',]...Copy the code
Root routing:
my_blog/urls.py
...
urlpatterns = [
...
# notice
path('notice/', include('notice.urls', namespace='notice')).]...Copy the code
Next up is the view. All of the previous views used view functions, but this time we’ll go a step further and use class views. Forget what a class view is, recall the previous class view section.
Writing a view:
notice/views.py
from django.shortcuts import render, redirect
from django.views import View
from django.views.generic import ListView
from django.contrib.auth.mixins import LoginRequiredMixin
from article.models import ArticlePost
class CommentNoticeListView(LoginRequiredMixin, ListView):
""" Notification List """
The name of the context
context_object_name = 'notices'
# template location
template_name = 'notice/list.html'
# Login redirection
login_url = '/userprofile/login/'
# unread notification query set
def get_queryset(self):
return self.request.user.notifications.unread()
class CommentNoticeUpdateView(View):
"" update notification status ""
# handle get requests
def get(self, request):
Get unread messages
notice_id = request.GET.get('notice_id')
# Update a single notification
if notice_id:
article = ArticlePost.objects.get(id=request.GET.get('article_id'))
request.user.notifications.get(id=notice_id).mark_as_read()
return redirect(article)
Update all notifications
else:
request.user.notifications.mark_all_as_read()
return redirect('notice:list')
Copy the code
There are two views.
Commentelistview: Inherited from the ListView, used to display all unread notifications. The get_queryset method returns the context object passed to the template, and the unread() method is provided in Django-notifications to get a collection of all unread notifications. The view also inherits ** “mixin classes” **LoginRequiredMixin, which requires you to be logged in to invoke the view.
Commenteupdateview: Inherits from A View and obtains basic methods such as get, POST, etc. Mark_as_read () and mark_all_AS_read are methods provided by the module to convert unread notifications to read. The if statement is used to determine whether to convert single or all unread notifications.
Repetition: If you have difficulty reading, please re-read the view section of the class, or go to the official documentation.
Now create a new urls.py and say:
notice/urls.py
from django.urls import path
from . import views
app_name = 'notice'
urlpatterns = [
# Notification list
path('list/', views.CommentNoticeListView.as_view(), name='list'),
Update notification status
path('update/', views.CommentNoticeUpdateView.as_view(), name='update'),]Copy the code
The second argument to path() can only accept functions, so don’t forget to call the as_view() method of the class view.
** Centralized notification processing requires a separate page. * * new templates/notice/list. The HTML template file:
Templates/notice/list. HTML {% extends "base. HTML" %} {% load staticfiles %} {% block title %} notifications {% endblock title %} {% block content %}<div class="container">
<div class="row mt-4 ml-4">
<a href="{% url "notice:update"%}"class="btn btn-warning" role="button">Clear all notifications</a>
</div>
<! -- Unread notification list -->
<div class="row mt-2 ml-4">
<ul class="list-group">
{% for notice in notices %}
<li class="list-group-item" id="notice_link">
<a href="{% url "notice:update"%}?article_id={{ notice.target.id}} ¬ice_id={{ notice.id }}"
target="_blank"
>
<span style="color: #5897fb;">
{{ notice.actor }}
</span>
在 <span style="color: #01a252;">{{ notice.target }}</span>{{notice. Verb}} instead!</a> {{ notice.timestamp|date:"Y/m/d H:i" }}</li>
{% endfor %}
</ul>
</div>
</div>
<style>
#notice_link a:link {
color: black;
}
#notice_link a:visited {
color: lightgrey;
}
</style>
{% endblock content %}
Copy the code
The template provides two main functions:
- Click on the
button
Button clears all unread notifications - Click on a single notification, convert it to a read notification, and go to the article on which this comment was made
The pseudo-class selector in the
The last is to fill in the entry:
templates/header.html
...
<a . href="{% url "notice:list" %}">Inform...</a>.Copy the code
And you’re done.
Open the server, use a normal account to make a few comments, then log in to the administrator account and enter the notification page:
And you can see that it looks pretty good. The result is that only unread notifications are displayed, although read notifications can also be displayed below for easy traceability.
conclusion
Notifications are very important, especially as your blog grows. You can also use it for other purposes, such as sending a notification to all your “followers” every time a new article is published, reminding them that they can read it. Specific how to extend apply, rely on your imagination to abound.
In the previous code, users will also be notified if they comment on themselves. This notification is not necessary, please correct it.
When encountering difficulties, find answers in the tutorial sample code.
- If you have any questions please leave a message on Doucet’s personal website and I will reply as soon as possible.
- Or Email me a private message: [email protected]
- Project code: Django_blog_tutorial