憑藉你勤奮的寫做,拜讀你文章的用戶愈來愈多,他們的評論也分散在衆多的文章之中。做爲博主,讀者的留言確定是要都看的;而讀者給你留言,天然也但願獲得回覆。css
怎麼將未讀的留言呈現給正確的用戶呢?總不能用戶本身去茫茫文章中尋找吧,那也太蠢了。給評論增長通知功能就是很流行的解決方案:好比微信朋友圈留言的通知、新浪微博留言的通知、以及各類社交平臺的「小紅點」。html
本篇將以django-notifications
爲基礎,很是高效的搭建一個簡易的通知系統。前端
前面的步驟咱們已經很熟悉了。python
首先安裝django-notifications
:git
(env) > pip install django-notifications-hq
複製代碼
註冊app:github
my_blog/settings.py
...
INSTALLED_APPS = [
...
'notifications',
...
]
...
複製代碼
在根路由中安裝路徑:django
my_blog/urls.py
...
import notifications.urls
urlpatterns = [
...
path('inbox/notifications/', include(notifications.urls, namespace='notifications')),
...
]
...
複製代碼
注意這裏的notifications.urls
沒有像以前同樣用字符串,是爲了確保模塊安裝到正確的命名空間中。bash
數據遷移:服務器
(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)
在 Django搭建我的博客 (target)
中對 你 (recipient)
發表了 (verb)
評論 (action_object)
。
由於咱們想要在用戶發表評論的時候發送通知,所以修改一下發表評論的視圖:
comments/views.py
...
from notifications.signals import notify
from django.contrib.auth.models 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">
<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 django.views.generic import ListView
from django.contrib.auth.mixins import LoginRequiredMixin
from article.models import ArticlePost
class CommentNoticeListView(LoginRequiredMixin, ListView):
"""通知列表"""
# 上下文的名稱
context_object_name = 'notices'
# 模板位置
template_name = 'notice/list.html'
# 登陸重定向
login_url = '/userprofile/login/'
# 未讀通知的查詢集
def get_queryset(self):
return self.request.user.notifications.unread()
class CommentNoticeUpdateView(View):
"""更新通知狀態"""
# 處理 get 請求
def get(self, request):
# 獲取未讀消息
notice_id = request.GET.get('notice_id')
# 更新單條通知
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)
# 更新所有通知
else:
request.user.notifications.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 style="color: #5897fb;">
{{ notice.actor }}
</span>
在 <span style="color: #01a252;">{{ 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>
...
複製代碼
這樣就完成了。
打開服務器,用一個普通帳號評論幾條,再登陸管理員帳號並進入通知頁面:
就能看到不錯的效果了。實現的效果是僅展現未讀通知,固然也能夠在下邊展現已讀通知,方便用戶追溯。
通知功能很是的重要,特別是在你的博客成長壯大了以後。你還能夠把它用在別的地方,好比每新發表一篇文章,就給你全部的「粉絲」推送一條通知,提醒他們能夠來拜讀了。具體如何擴展運用,就靠你腦洞大開了。
**課後做業:**前面的代碼中,若是用戶本身評論本身,一樣也會收到通知。這種通知並無必要,請修正它。
遇到困難,在教程示例代碼找答案吧。