Django搭建个人博客:用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.urlsurlpatterns = [...path('inbox/notifications/', include(notifications.urls, namespace='notifications')),... ] ...注意這里的notifications.urls沒有像之前一樣用字符串,是為了確保模塊安裝到正確的命名空間中。
數據遷移:
(env) > python manage.py migrateapp就安裝好了。
接下來你就可以在項目的任何地方發送通知了!像這樣:
from notifications.signals import notifynotify.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是空的,接下來就處理。
未讀與已讀
既然是通知,那么肯定能夠分成**”未讀的“和”已讀的“**兩種。在適當的時候,未讀通知又需要轉換為已讀的?,F在我們來開發功能集中處理它。
通知是一個獨立的功能,以后有可能在任何地方用到,放到評論app中似乎并不合適。
所以新建一個app:
(env) > python manage.py startapp notice注冊:
my_blog/settings.py... INSTALLED_APPS = [...'notice', ] ...根路由:
my_blog/urls.py... urlpatterns = [...# noticepath('notice/', include('notice.urls', namespace='notice')), ] ...接下來就是視圖了。之前所有的視圖都是用的視圖函數,這次我們更進一步,用類視圖來完成。忘記什么是類視圖的,回憶一下前面類的視圖章節。
編寫視圖:
notice/views.pyfrom 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 ArticlePostclass 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.pyfrom django.urls import path from . import viewsapp_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> ...這樣就完成了。
打開服務器,用一個普通賬號評論幾條,再登錄管理員賬號并進入通知頁面:
就能看到不錯的效果了。實現的效果是僅展示未讀通知,當然也可以在下邊展示已讀通知,方便用戶追溯。
總結
通知功能非常的重要,特別是在你的博客成長壯大了之后。你還可以把它用在別的地方,比如每新發表一篇文章,就給你所有的“粉絲”推送一條通知,提醒他們可以來拜讀了。具體如何擴展運用,就靠你腦洞大開了。
**課后作業:**前面的代碼中,如果用戶自己評論自己,同樣也會收到通知。這種通知并沒有必要,請修正它。
遇到困難,在教程示例代碼找答案吧。
- 有疑問請在杜賽的個人網站留言,我會盡快回復。
- 或Email私信我:dusaiphoto@foxmail.com
- 項目完整代碼:Django_blog_tutorial
總結
以上是生活随笔為你收集整理的Django搭建个人博客:用django-notifications实现消息通知的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Microsoft Graph noti
- 下一篇: AIX基本操作命令