为了账号安全,请及时绑定邮箱和手机立即绑定

新的聊天消息通知 Django 频道

新的聊天消息通知 Django 频道

明月笑刀无情 2021-12-29 20:53:03
我已经Django Channels 2.1.2按照教程在我的 Django 应用程序中进行了设置,现在需要为新消息设置通知系统。我想以最简单的方式做到这一点。我可以通过浏览器推送通知来做到这一点,但我不想那样做。我希望它像 Stack Overflow 一样,其中有一个红色数字代表新消息的实例。这里的一个答案说对于通知,您只需要两个模型:User和Notification。在连接时将范围设置为当前经过身份验证的用户。post_save在您的Notification模型上设置 信号以触发消费者方法向通知对象的用户发送消息。——我正在努力思考这会是什么样子,我已经有了一个User模型但没有Notification一个。聊天仅在 2 个用户之间进行,它不是聊天室,而是更多的聊天线程。2个html模板是inbox.html和thread.html
查看完整描述

2 回答

?
绝地无双

TA贡献1946条经验 获得超4个赞

实现通知系统的一种简单方法可以是:


当你想显示一条新消息时,一旦你在 websocket 上收到消息,就使用 JS 操作 HTML。每当与元素进行交互时,这意味着用户已阅读通知,使用 websocket 将消息发送回服务器。


您Notification可以拥有ForeignKeys用户和消息以及BooleanField阅读状态。每当您向用户发送消息时,都应该在消息中附加 notification_id,


#consumer.py

async def websocket_receive(self, event):

        # when a message is received from the websocket

        print("receive", event)


        message_type = event.get('type', None)  #check message type, act accordingly

        if message_type == "notification_read":

             # Update the notification read status flag in Notification model.

             notification = Notification.object.get(id=notification_id)

             notification.notification_read = True

             notification.save()  #commit to DB

             print("notification read")


        front_text = event.get('text', None)

        if front_text is not None:

            loaded_dict_data = json.loads(front_text)

            msg =  loaded_dict_data.get('message')

            user = self.scope['user']

            username = 'default'

            if user.is_authenticated:

                username = user.username

            myResponse = {

                'message': msg,

                'username': username,

                'notification': notification_id  # send a unique identifier for the notification

            }

            ...

在客户端,


// thread.html

socket.onmessage = function(e) {

    var data = JSON.parse(event.data);

    // Find the notification icon/button/whatever and show a red dot, add the notification_id to element as id or data attribute.

}

...


$(#notification-element).on("click", function(){

    data = {"type":"notification_read", "username": username, "notification_id": notification_id};

    socket.send(JSON.stringify(data));

});


您可以根据需要将单个/所有未读通知标记为已读。



查看完整回答
反对 回复 2021-12-29
?
RISEBY

TA贡献1856条经验 获得超5个赞

我无法将其标记为重复,因为它有赏金。但解决方案是,您需要两个以上的模型。根据这篇文章,你models.py应该看起来像这样:


class MessageThread(models.Model):

    title = models.CharField()

    clients = models.ManyToManyField(User, blank=True)


class Message(models.Model):

    date = models.DateField()

    text = models.CharField()

    thread = models.ForeignKey('messaging.MessageThread', on_delete=models.CASCADE)

    sender = models.ForeignKey(User, on_delete=models.SET_NULL)

你consumers.py应该是这样的:


class ChatConsumer(WebSocketConsumer):

    def connect(self):

        if self.scope['user'].is_authenticated:

            self.accept()

            # add connection to existing groups

            for thread in MessageThread.objects.filter(clients=self.scope['user']).values('id'):

                async_to_sync(self.channel_layer.group_add)(thread.id, self.channel_name)

            # store client channel name in the user session

            self.scope['session']['channel_name'] = self.channel_name

            self.scope['session'].save()


    def disconnect(self, close_code):

        # remove channel name from session

        if self.scope['user'].is_authenticated:

            if 'channel_name' in self.scope['session']:

                del self.scope['session']['channel_name']

                self.scope['session'].save()

            async_to_sync(self.channel_layer.group_discard)(self.scope['user'].id, self.channel_name)


查看完整回答
反对 回复 2021-12-29
  • 2 回答
  • 0 关注
  • 193 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信