【转】django-notifications实现消息通知
凭借你勤奋的写作,拜读你⽂章的⽤户越来越多,他们的评论也分散在众多的⽂章之中。作为博主,读者的留⾔肯定是要都看的;⽽读者给你留⾔,⾃然也希望得到回复。
怎么将未读的留⾔呈现给正确的⽤户呢?总不能⽤户⾃⼰去茫茫⽂章中寻吧,那也太蠢了。给评论增加通知功能就是很流⾏的解决⽅案:⽐如朋友圈留⾔的通知、新浪微博留⾔的通知、以及各种社交平台的“⼩红点”。
本篇将以django-notifications为基础,⾮常⾼效的搭建⼀个简易的通知系统。
发送通知
前⾯的步骤我们已经很熟悉了。
⾸先安装django-notifications:
(env) > pip install django-notifications-hq
注册app:
my_blog/settings.py
...
INSTALLED_APPS = [
...
'notifications',
...
]
...
在根路由中安装路径:
my_blog/urls.py
...
import notifications.urls
urlpatterns = [
...
path('inbox/notifications/', include(notifications.urls, namespace='notifications')),
...
]
...
注意这⾥的notifications.urls没有像之前⼀样⽤字符串,是为了确保模块安装到正确的命名空间中。
数据迁移:
(env) > python manage.py migrate
app就安装好了。
接下来你就可以在项⽬的任何地⽅发送通知了!像这样:
from notifications.signals import notify
notify.send(actor, recipient, verb, target, action_object)
其中的参数释义:
actor:发送通知的对象
recipient:接收通知的对象
verb:动词短语
target:链接到动作的对象(可选)
action_object:执⾏通知的对象(可选)
有点绕,举个栗⼦:(actor)在(target)中对 [你]() (recipient) [发表了]() (verb) [评论]() (action_object)。
因为我们想要在⽤户发表评论的时候发送通知,因此修改⼀下发表评论的视图:
comments/views.py
...
from notifications.signals import notify
dels import User
...
def post_comment(...):
...
# 已有代码,创建新回复
if comment_form.is_valid():
...
# 已有代码,⼆级回复
if parent_comment_id:
...
# 新增代码,给其他⽤户发送通知
if not parent_comment.user.is_superuser:
notify.send(
request.user,
recipient=parent_comment.user,
verb='回复了你',
target=article,
action_object=new_comment,
)
return HttpResponse('200 OK')
new_comment.save()
# 新增代码,给管理员发送通知
if not request.user.is_superuser:
notify.send(
request.user,
recipient=User.objects.filter(is_superuser=1),
verb='回复了你',
target=article,
action_object=new_comment,
)
return redirect(article)
...
2019/6/4 修正此代码。旧代码错误的将发送给管理员的notify放在了new_comment.save()的前⾯,导致action_object存储为NULL。
增加了两条notify的语句,分别位于两个if语句中:
第⼀个notify:⽤户之间可以互相评论,因此需要发送通知。if语句是为了防⽌管理员收到重复的通知。
第⼆个notify:所有的评论都会给管理员(也就是博主)发送通知,除了管理员⾃⼰。
其他的代码没有变化,注意位置不要错就⾏了。你可以试着发送⼏条评论,然后打开SQLiteStudio,查看notifications_notification表中的数据变化。
有效代码实际上只有4⾏,我们就完成了创建、发送通知的功能!相信你已经逐渐体会到运⽤第三⽅库带来的便利了。这就是站在了“巨⼈们”的肩膀上。
⼩红点
后台创建通知的逻辑已经写好了,但是如果不能在前端显⽰出来,那也没起到作⽤。
⽽前端显⽰消息通知⽐较流⾏的是“⼩红点”,流⾏得都已经泛滥了,尽管很多软件其实根本就不需要。另⼀种形式是消息徽章,即⼀个红⾊⽅框中带有消息条⽬的计数。这两种⽅式都会⽤到博客页⾯中。
在位置的选择上,header是很合适的,因为它在博客的所有位置都会显⽰,很符合通知本⾝的定位。
因此修改header.html:
templates/header.html
<!-- 引⼊notifications的模板标签 -->
{% load notifications_tags %}
{% notifications_unread as unread_count %}
...
<!-- 已有代码,⽤户下拉框 -->
<li class="nav-item dropdown">
html实现用户注册登录代码
<a class="nav-link dropdown-toggle" ...>
<!-- 新增代码,⼩红点 -->
{% 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>
<!-- 已有代码,下拉框中的链接 -->
<div class="dropdown-menu" ...>
<!-- 新增代码,通知计数 -->
<a class="dropdown-item" href="#">通知
{% if unread_count %}
<span class="badge badge-danger">{{ unread_count }}</span>
{% endif %}
</a>
...
<a ...>退出登录</a>
</div>
</li>
...
django-notifications⾃带简易的模板标签,可以在前台模板中调⽤重要的通知相关的对象,在顶部引⼊就可以使⽤了。⽐如unread_count是当前⽤户的未读通知的计数。
Bootstrap⾃带有徽章的样式,但是却没有⼩红点的样式(⾄少我没有到),所以就只能⽤svg⾃⼰画了,好在也不难。
svg是绘制⽮量图形的标签,这⾥就不展开讲了,感兴趣请⾃⾏搜索相关⽂章。
随便评论⼏条,刷新页⾯看⼀看:
效果不错。但是链接的href是空的,接下来就处理。
未读与已读
既然是通知,那么肯定能够分成”未读的“和”已读的“两种。在适当的时候,未读通知⼜需要转换为已读的。现在我们来开发功能集中处理它。通知是⼀个独⽴的功能,以后有可能在任何地⽅⽤到,放到评论app中似乎并不合适。
所以新建⼀个app:
(env) > python manage.py startapp notice
注册:
my_blog/settings.py
...
INSTALLED_APPS = [
...
'notice',
]
...
根路由:
my_blog/urls.py
...
urlpatterns = [
...
# notice
path('notice/', include('notice.urls', namespace='notice')),
]
.
..
接下来就是视图了。之前所有的视图都是⽤的视图函数,这次我们更进⼀步,⽤类视图来完成。忘记什么是类视图的,回忆⼀下前⾯章节。编写视图:
notice/views.py
from django.shortcuts import render, redirect
from django.views import View
from ic import ListView
ib.auth.mixins import LoginRequiredMixin
dels import ArticlePost
class CommentNoticeListView(LoginRequiredMixin, ListView):
"""通知列表"""
# 上下⽂的名称
context_object_name = 'notices'
# 模板位置
template_name = 'notice/list.html'
# 登录重定向
login_url = '/userprofile/login/'
# 未读通知的查询集
def get_queryset(self):
ifications.unread()
class CommentNoticeUpdateView(View):
"""更新通知状态"""
# 处理 get 请求
def get(self, request):
# 获取未读消息
notice_id = ('notice_id')
# 更新单条通知
if notice_id:
article = (id=('article_id'))
(id=notice_id).mark_as_read()
return redirect(article)
# 更新全部通知
else:
ifications.mark_all_as_read()
return redirect('notice:list')
视图共两个。
CommentNoticeListView:继承⾃ListView,⽤于展⽰所有的未读通知。get_queryset⽅法返回了传递给模板的上下⽂对象,unread()⽅法是django-notifications提供的,⽤于获取所有未读通知的集合。另外视图还继承了“混⼊类”LoginRequiredMixin,要求调⽤此视图必须先登录。CommentNoticeUpdateView:继承⾃View,获得了如get、post等基础的⽅法。mark_as_read()、mark_all_as_read都是模块提供的⽅法,⽤于将未读通
知转换为已读。if语句⽤来判断转换单条还是所有未读通知。
重复:阅读有困难的同学,请重新阅读查阅。
接下来就是新建urls.py了,写⼊:
notice/urls.py
from django.urls import path
from . import views
app_name = 'notice'
urlpatterns = [
# 通知列表
path('list/', views.CommentNoticeListView.as_view(), name='list'),
# 更新通知状态
path('update/', views.CommentNoticeUpdateView.as_view(), name='update'),
]
path()的第⼆个参数只能接收函数,因此别忘了要调⽤类视图的as_view()⽅法。
集中处理通知需要⼀个单独的页⾯。新建templates/notice/list.html模板⽂件:
templates/notice/list.html
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}
通知
{% 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">清空所有通知</a>
</div>
<!-- 未读通知列表 -->
<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 >
{{ notice.actor }}
</span>
在 <span >{{ notice.target }}</span> {{ notice.verb }}。
</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 %}
模板中主要提供了两个功能:
点击button按钮清空所有未读通知
点击单个通知,将其转换为已读通知,并前往此评论所在的⽂章
末尾<style>标签中的伪类选择器,作⽤是将已经点击过的通知字体颜⾊转换为浅灰⾊,优化⽤户体验。
最后就是补上⼊⼝:
templates/header.html
...
<a ... href="{% url "notice:list" %}">通知...</a>
...
这样就完成了。
打开服务器,⽤⼀个普通账号评论⼏条,再登录管理员账号并进⼊通知页⾯:
就能看到不错的效果了。实现的效果是仅展⽰未读通知,当然也可以在下边展⽰已读通知,⽅便⽤户追溯。
总结
通知功能⾮常的重要,特别是在你的博客成长壮⼤了之后。你还可以把它⽤在别的地⽅,⽐如每新发表⼀篇⽂章,就给你所有的“粉丝”推送⼀条通知,提醒他们可以来拜读了。具体如何扩展运⽤,就靠你脑洞⼤开了。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。