用Django_notifications实现网站消息通知

     阅读:28

前言

        本文章记录在网站搭建过程中使用django_notifications的方法,使用的是前后端不分离的方法,完全作为记录以方便日后浏览使用,故仅供浏览者参考使用。

        以下是本篇文章正文内容


目录

前言

一、准备工作

1.安装django-notifications:

2.在项目settings文件中注册app

3.在根路由中写入路径

4.数据迁移

二、基本使用

1. 生成通知

2. 前端显示数量

3. 前端显示未读通知

4. 未读变已读

三、灵活使用

1. 软删除

2. 前端显示已读通知

总结

Everything is going smoothly


一、准备工作

1.安装django-notifications

(env) > pip install django-notifications-hq

2.在项目settings文件中注册app

objects_web/settings.py

...
INSTALLED_APPS = [
    ...
    'notifications',
    ...
]

3.在根路由中写入路径

objects_web/urls.py

...
import notifications.urls

urlpatterns = [
    ...
    # 通知
    path('inbox/notifications/', include(notifications.urls, namespace='notifications')),
    ...
]
...

4.数据迁移

(env) > python manage.py migrate

二、基本使用

1. 生成通知

你可以在任意的地方导入并发送消息

from notifications.signals import notify

notify.send(actor, recipient, verb, action_object, 
target, level, description, public,timestamp, **kwargs)

上面是完整的语法,参数分别为:

  • actor(发件人):任何类型的对象。(必需)如果打算使用关键字参数,要使用sender
  • recipient(收件人): 一组或一个用户查询集或列表的用户(必需的)。
  • verb(动作): 一个字符串(必需的)。
  • action_object:任何类型的对象(可选的)。
  • target(目标):任何类型的对象(可选的)。
  • level(等级):Notification.LEVELS ('success', 'info', 'warning', 'error') 之一(可选的)。
  • description(描述): 一个字符串(可选的)。
  • public(公共的):一个布尔值(默认值=True)(可选的)。
  • timestamp(时间戳)

 其中,发件人(actor),收件人(recipient),动作(verb)这三项是在使用时必须传入的,其他项可根据实际情况使用。

我在项目根部录下创建了一个notifications.py文件,用来放通知功能相关的代码

然后把发送通知的方法封装成了一个函数,直接上代码:

objects_web/notification.py


from notifications.signals import notify

def send_notifications(actor, verb, recipient, target=None, 
                       description=None, **kwargs):
    """
        这里原本放的是上文各个参数的说明
    """
    notify.send(sender=actor,
                recipient=recipient,
                verb=verb,
                target=target,
                description=description,
                **kwargs
                )

 然后在任意app下的views.py文件的任意位置中调用:

userProfile/views.py


from userProfile.notifications import send_notifications

send_notifications(request.user, "转正申请", request.user,
                     description="sp",level="danger")

这样就生成了一条简单的通知啦!

2. 前端显示数量

首先,必须先实时看到我有多少条未读的通知:

templates/notifications_unread.html

<!-- 引入notifications的模板标签 -->
{% load notifications_tags %}
{% notifications_unread as unread_count %}

<div class="wrapper">

    <!-- Navbar -->
    <nav class="main-header navbar navbar-expand-md navbar-light navbar-white">
        <div class="container">
            <!-- Right navbar links -->
            <ul class="order-1 order-md-3 navbar-nav navbar-no-expand ml-auto">
                <li class="nav-item dropdown">
                    <a class="nav-link" data-toggle="dropdown" href="#">
                        <i class="far fa-bell"></i>
                        {% if unread_count %}
                            <span class="badge badge-warning navbar-badge">
                        {{ unread_count }}</span>{% endif %}
                    </a>
                    <div class="dropdown-menu dropdown-menu-lg dropdown-menu-right">
                    <span class="dropdown-item dropdown-header">{% if unread_count %}{{ unread_count }}条通知{% else %}
                        暂无通知{% endif %}</span>
                        <div class="dropdown-divider"></div>
                        {% if unread_count %}
                            <a href="{% url "userProfile:user_notifications" %}" class="dropdown-item">
                                <i class="fa fa-comment"></i> {{ unread_count }} 条未读通知
                            </a>
                        {% endif %}
                        <div class="dropdown-divider"></div>
                        <a href="{% url "userProfile:user_notifications" %}" class="dropdown-item dropdown-footer">查看所有<i
                                class="fas fa-arrow-circle-right"></i></a>
                    </div>
                </li>
            </ul>
        </div>
    </nav>

django-notifications自带简易的模板标签,可以在前台模板中调用重要的通知相关的对象,在顶部引入就可以使用了。unread_count是当前用户的未读通知的计数。

请大家忽略我的html代码,其实比较重要的就是这一句:

<!-- 如果有通知,显示通知的数量;样式可以随便设置 -->
{% if unread_count %}
       {{ unread_count }}
{% endif %}

然后随便发几条通知,看下效果

 这样未读通知的数量就可以显示啦。

3. 前端显示未读通知

django-notifications提供了获取用户未读信息的方法,我同样把他封装成一个函数方法

传入用户的对象,返回用户未读通知列表

objects_web/notification.py


def get_unread_list(user):
    """
    return:返回用户未读列表
    """
    return user.notifications.unread()

在view.py文件中,获取用户未读信息传到前端

userProfile/views.py


def user_notifications(request):
    unread_list = get_unread_list(request.user)
    return render(request, "indexuser/userinfo/notifications_unread.html", {"unread_list": unread_list})

在前端遍历这个列表

同样的,请忽略前端代码,主要看用法

templates/notifications_unread.html

{% for notice in unread_list %}
    {% if notice.description  == "sp" %}
        <tr>
            <td class="mailbox-star">
                <i class="fas fa-star text-{{ notice.level }}"></i>
            </td>
            <td class="mailbox-name">
                <a><b class="text-primary">{{ notice.verb }}</b></a>
            </td>
            <td class="mailbox-subject">
                您收到了来自<bclass="text-success">{{ notice.actor }}</b>的{{ notice.verb }}
            </td>
            <td class="mailbox-date">
                <b>{{ notice.timestamp }}</b>
            </td>
            <td class="mailbox-attachment">
                <a href="{% url 'userProfile:approval_details' %}?id= 
                {{notice.target.object_id }}&type={{ notice.target.type }}" title="查看">
                <span class="text-primary"><i class="fas fa-paperclip"></i></span>
                </a>
            </td>
            <td class="mailbox-attachment">
                <a href="{% url "userProfile:user_change_unread" %}?notice_id={{ notice.id 
                 }}" title="已读"><span class="text-success"><i class="fa fa-check"></i>     
                </span></a>
            </td>
        </tr>
    {% endif %}
{% endfor %}

看下效果

 OK,前端已经可以查看未读的通知了。

4. 未读变已读

django-notifications同样提供了转变的方法,继续写函数

userProfile/views.py


# 未读变更为已读
def change_unread(request):
    notice_id = request.GET.get('notice_id')
    if notice_id:
        # 更新一条
        request.user.notifications.get(id=notice_id).mark_as_read()
        return redirect("userProfile:user_notifications")
    else:
        # 更新全部
        request.user.notifications.mark_all_as_read()
        return redirect("userProfile:user_notifications")

为了实现单条已读和全部已读,我把它分成了两种情况的请求

一种是前端带着该条通知的id请求,一种是不带,则全部更新。

上前段代码,单条的已读就在上文的内容中,可以试着找一下,我这里把它重新摘出来。

templates/notifications_unread.html

<!-- 单条带id的请求 -->
<td class="mailbox-attachment">
     <a href="{% url "userProfile:user_change_unread" %}?notice_id={{ notice.id }}"
      title="已读"><span class="text-success"><i class="fa fa-check"></i></span></a>
/td>

<!-- 全部不带id的请求 -->
<button type="button" class="btn btn-tool">
    <a href="{% url "userProfile:user_change_unread" %}"
        class="text-success font-weight-bold">
        <i class="fa fa-check"></i>全部已读
    </a>
</button>

这样,通过点击单条通知后的对勾,或者点击右上角的全部已读,就实现了未读转已读的功能了~

同时,其实到这里,通知的基本功能已经实现了,但是如果想要查看已读的信息该怎么办呢,目前这样显然是不行的,接着往下。

三、灵活使用

1. 软删除

如果只按上面的用法,已读信息其实是已经被直接删除的,我们就无法再查看已读的信息。

如果想要保留已读的通知,需要在settings.py文件下做一项配置,实现“软删除”

settings.py写入:

objects_web/settings.py


...
DJANGO_NOTIFICATIONS_CONFIG = { 'USE_JSONFIELD': True}
...

当写入这条配置之后,unread和read的方法将包含一个过滤器:deleted=False。

read方法其实就是获取已读信息的方式。

接下来,我们找到已读的信息,将它们传到前端

2. 前端显示已读通知

userProfile/views.py


def notifications_read(request):
    read_list = get_read_list(request.user)
    return render(request, "indexuser/userinfo/notifications_read.html", {"read_list": read_list})

前端的遍历方法同上一样,代码就不再重复,直接看效果

这样已读的通知就出来了

同样,已读的信息也可以彻底进行删除,继续写函数方法,同样分为单条删除和一起删除

使用QuerySet.mark_all_as_deleted()方法

userProfile/views.py


# 已读变更为删除
def user_delete_read(request):
    notice_id = request.GET.get('notice_id')
    if notice_id:
        request.user.notifications.filter(id=notice_id).mark_all_as_deleted()
        return redirect("userProfile:notifications_read")
    # 删除全部已读通知
    else:
        request.user.notifications.read().mark_all_as_deleted()
        return redirect("userProfile:notifications_read")

需要注意的是,因为mark_all_as_deleted()是NotificationQuerySet的方法,所以不能用get方法来获取单条通知,必须用filter,哪怕它只有一条。

OK,到这里,基本的已读、未读、未读转已读、已读删除就全部搞定了,还有很多实用的方法,有特殊需求的可以去django-notifications的官方网站查看一下,那里还提供了各种方法

django-notifications官网https://pypi.org/project/django-notifications-hq/

总结

目前这些内容已经足够当前项目的使用,官网还提供了实时更新通知的JavaScript方法,以后有需要的时候可以用一下,本文仍然只作为个人平时的记录和后期的查看用,这里记录两个大佬的博客地址,全是干货,涵盖的内容很多,也可做平时学习用:

杜赛的博客https://www.dusaiphoto.com/topic/刘江的博客https://www.liujiangblog.com/blog/

Everything is going smoothly.