Search code examples
djangodjango-channels

Django channels username sender


I am new to Django channels , i followed the documentation tutorial and i made a Django chat room , so far i can send and recieve messages , but the probleme here the sender is unknown , i tried to send the username but its not working , i get the username printed in the server but in the front i get the actual login username?? i am confused ?

consumer.py :

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'chat_%s' % self.room_name
        self.user = self.scope["user"]
        # Join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, close_code):
        # Leave room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    # Receive message from WebSocket
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        # Send message to room group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )

    # Receive message from room group
    async def chat_message(self, event):
        message = event['message']
        print(self.user.username)

        # Send message to WebSocket
        await self.send(text_data=json.dumps({
            'message': message,
            'username' : str(self.user.username),
        }))

room.html :

<!-- chat/templates/chat/room.html -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Chat Room</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<div style="width:800px; margin:0 auto;">username :
     <a  id="username" href="">{{ user.get_username }}</a>
     <textarea id="chat-log" cols="100" rows="20"></textarea><br/>
    <input id="chat-message-input" type="text" size="75"/><br/>
    <input id="chat-message-submit" type="button" value="Send"/>
</div>

</body>
<script>
    var roomName = {{ room_name_json }};

    var chatSocket = new WebSocket(
        'ws://' + window.location.host +
        '/ws/chat/' + roomName + '/');

    chatSocket.onmessage = function(e) {
        var data = JSON.parse(e.data);
        var message = data['message'];
        console.log(e.data)

        document.querySelector('#chat-log').value += ( message + '\n');
    };

    chatSocket.onclose = function(e) {
        console.error('Chat socket closed unexpectedly');
    };

    document.querySelector('#chat-message-input').focus();
    document.querySelector('#chat-message-input').onkeyup = function(e) {
        if (e.keyCode === 13) {  // enter, return
            document.querySelector('#chat-message-submit').click();
        }
    };

    document.querySelector('#chat-message-submit').onclick = function(e) {
        var messageInputDom = document.querySelector('#chat-message-input');
        var message = messageInputDom.value;
        chatSocket.send(JSON.stringify({
            'message': message
        }));

        messageInputDom.value = '';
    };
</script>
</html>


Solution

  • When the user connects, he gets a separate instance of the ChatConsumer and you set the self.user. If he receives a message from another channel, the self.user does not change, it is still the one you set for him. So to show the username of the sender, you have to send it along with the message like this:

        ...
        # Receive message from WebSocket
        async def receive(self, text_data):
            text_data_json = json.loads(text_data)
            message = text_data_json['message']
    
            # Send message to room group
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type': 'chat_message',
                    'message': message,
                    'username': self.user.username
                }
            )
    
        # Receive message from room group
        async def chat_message(self, event):
            message = event['message']
            username = event['username']
            print(username)
    
            # Send message to WebSocket
            await self.send(text_data=json.dumps({
                'message': message,
                'username' : username,
            }))
    

    It is important to note that separate instances of ChatConsumer run the methods receive and chat_message, hence the self.user in those methods are different. While the receive method is executed in the sender's channel, the chat_message method is executed in the channels of the receivers which will also include the sender in this case, since he is in the same group as the receivers. For example, to see if the message you received was sent by you, you could do something like this in the chat_message method:

    if event['username'] == self.user.username:
        ...