New chat message notification Django Channels

后端 未结 2 1574
时光取名叫无心
时光取名叫无心 2020-12-13 21:36

I\'ve got Django Channels 2.1.2 set up in my Django app by following a tutorial and now need to set up a notification system for new messages. I want to do this

相关标签:
2条回答
  • 2020-12-13 22:25

    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)
    
    0 讨论(0)
  • 2020-12-13 22:30

    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.

    0 讨论(0)
提交回复
热议问题