New chat message notification Django Channels

对着背影说爱祢 提交于 2019-12-03 12:22:56

One easy way to implement a notification system can be:

When you want to show a new message, manipulate HTML using JS as soon as you get a message on the websocket. And whenever the element has been interacted with, which means the user has read the notification, send a message back to server using the websocket.

Your Notification can have ForeignKeys to user and the message along with a BooleanField for read status. Whenever you are sending the message to the user, you should append the notification_id along the message,

#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
            }
            ...

On the client side,

// 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));
});

You can mark individual/all unread notifications as read according to your need.

I did something similar for a training project, you can check that out for ideas. Github link.

I couldn't mark this as a duplicate, because there is a bounty on it. But the solution is, you need more than two models. According to this post, your models.py should look something like this:

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)

Your consumers.py should look like this:

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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!