Django Channels message read and unread

I am new to django channels and trying to build a chat app, I met some trouble in developing read and unread functioning, I hope you can give me a hand.


chat consumer has a very simple structure:

room name chat_1 is for user 1 to receive message. whoever connects to it, can send message to user 1, and database save method is defined in consumer which takes self.scope["user"] as sender, and self.room_name as receiver to create message record and mark it as unread

user has a friend list, by clicking on the name, load all messages, meanwhile mark all messages to read, I did this by ajax function rather than ws as user click away from talking target.

but here is one scenario, where two user is on each other's page and does not click anyone else, I need to init the message with read already when creating to database.

let's say user_1 is talking to user_22, user_1 connect to many ws, but currently facing ws_22 to send message to user_22. In the receive method, how can I determine whether user_22 is currently facing ws_1 which waiting for the message?

by saying facing, I does not mean connect to the websocket, user connect to many ws at the same time corresponding to their friends (each friend has a unique ws to receive message) I mean to turn to the chat bubbles page with target user by clicking user avatar.


if you are confused or stressed by any of my expression, I am sorry for troubling. however, if you have any suggestion or any thing for me to look at, I will be more than grateful.

chat consumer


class ChatConsumer(AsyncJsonWebsocketConsumer):
    @staticmethod
    def send_chat(pk, message):
        channel_layer = get_channel_layer()
        async_to_sync(channel_layer.group_send)(
            'chat_{}'.format(pk), 
            {
                'type': 'chat_message', 
                'message': message, 
            }
        )

    @staticmethod
    @database_sync_to_async
    def userOnline(pk):
        user = User.objects.get(pk=pk)
        user.chatProfile.online = True
        user.save()
    
    @staticmethod
    @database_sync_to_async
    def userOffline(pk):
        user = User.objects.get(pk=pk)
        user.chatProfile.online = False
        user.save()
    
    @staticmethod
    @database_sync_to_async
    def newText(text, style, sender_pk, receiver_pk):
        msg = Message(
            sender=User.objects.get(pk=sender_pk).chatProfile, 
            receiver=User.objects.get(pk=receiver_pk).chatProfile, 
            text=text,
            style=style, 
        )
        msg.save()
        return msg
    
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['pk']
        self.room_group_name = 'chat_%s' % self.room_name

        await self.channel_layer.group_add(
            self.room_group_name, 
            self.channel_name, 
        ) 

        await self.accept()

        user = self.scope['user']
        await ChatConsumer.userOnline(user.pk)
        
        await self.channel_layer.group_send(
            'chat_{}'.format(self.room_name), 
            {
                'type': 'online_status', 
                'message': 'online', 
            }
        )
    
    async def disconnect(self, close_code):
        user = self.scope['user']
        await ChatConsumer.userOffline(user.pk)
        await self.channel_layer.group_send(
            'chat_{}'.format(self.room_name), 
            {
                'type': 'online_status', 
                'message': 'offline', 
            }
        )

        await self.channel_layer.group_discard(
            self.room_group_name, 
            self.channel_name, 
        )

    async def receive(self, text_data=None, bytes_data=None):
        text_data_json = json.loads(text_data)
        if text_data_json['type'] == 'text':
            message = text_data_json['message']
            style = None
            try:
                style = text_data_json['style']
            except KeyError:
                pass
            '''
            sender: self.scope["user"].pk
            receiver: self.room_name
            '''
            await ChatConsumer.newText(
                message, 
                style, 
                self.scope["user"].pk, 
                int(self.room_name), 
            )

        await self.channel_layer.group_send(
            self.room_group_name, 
            {
                'type': 'chat_message', 
                'message': message, 
                'style': style, 
            }
        )

    async def chat_message(self, event):
        await self.send(text_data=json.dumps({
            'message': event['message'], 
            'style': event['style'], 
            'user': self.scope['user'].pk, 
        }))

    async def online_status(self, event):
        await self.send(text_data=json.dumps({
            'type': 'online', 
            'message': event['message'], 
            'user': self.scope['user'].pk, 
        }))

message model

class Message(models.Model):
    sender = models.ForeignKey(ChatProfile, on_delete=models.CASCADE, related_name='sent')
    receiver = models.ForeignKey(ChatProfile, on_delete=models.CASCADE, related_name='received')

    text = models.TextField(blank=1, null=1)
    image = models.FileField(upload_to='chatprofile_image', blank=1, null=1)
    file = models.FileField(upload_to='chatprofile_file', blank=1, null=1)
    audio = models.BinaryField(blank=1, null=1) 

    createTime = models.DateTimeField(default=now)
    read = models.BooleanField(default=False)
    style = models.CharField(max_length=50, blank=1, null=1)

chat profile model

class ChatProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='chatProfile')
    # mutual added relationship
    friends = models.ManyToManyField(User, blank=1, related_name='friends')
    online = models.BooleanField(default=False)
Back to Top