Press ESC to close

Build a Real-Time Chat Application Using Django Channels and WebSockets in Python

Photo by freepik

Building a real-time chat application using Django Channels and WebSockets is an excellent project to demonstrate how to handle asynchronous web protocols in Django. Here’s a step-by-step guide to help you build a basic real-time chat application.

Prerequisites

Before starting, make sure you have the following installed:

  1. Python (preferably 3.7+)
  2. Django (install using pip install django)
  3. Django Channels (install using pip install channels)
  4. Redis (for channel layers and WebSocket communication.

Also read: “Create a Program to Download Images from a Website Using Scrapy in Python”

Step-by-Step Guide

1. Set Up a Django Project

First, create and set up a Django project:

django-admin startproject chat_app
cd chat_app
python manage.py startapp chat

2. Install Django Channels

Install Django Channels by running:

pip install channels

Then, add channels to your INSTALLED_APPS in settings.py:

# chat_app/settings.py
INSTALLED_APPS = [
    # Django apps...
    'channels',
    'chat',  # Add your chat app here
]

# Specify ASGI application
ASGI_APPLICATION = 'chat_app.asgi.application'

3. Configure Channels and Redis for Channel Layers

Django Channels uses a channel layer to manage WebSockets. Redis is a popular choice for this.

Install Redis and Django’s Redis support:

pip install channels_redis

Now, add Redis configuration for Channels in settings.py:

# chat_app/settings.py
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],  # Adjust if your Redis server is elsewhere
        },
    },
}

4. Create an ASGI Configuration

Create the asgi.py file for ASGI server configuration. It will route WebSocket requests:

# chat_app/asgi.py
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chat.routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'chat_app.settings')

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": AuthMiddlewareStack(
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),
})

5. Create Routing for WebSockets

In your chat app, create a routing.py file to define WebSocket routes:

# chat/routing.py
from django.urls import re_path
from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer.as_asgi()),
]

6. Build the Consumer to Handle WebSocket Connections

Consumers manage WebSocket connections. Create a consumers.py file in your chat app:

# chat/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = f'chat_{self.room_name}'

        # 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']

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

7. Define the Chat Room View

In your views.py file, create a view that renders the chat room:

# chat/views.py
from django.shortcuts import render

def room(request, room_name):
    return render(request, 'chat/room.html', {
        'room_name': room_name
    })

8. Configure URL Routing for the Views

In chat/urls.py, set up URL routing for the chat room:

# chat/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('<str:room_name>/', views.room, name='room'),
]

Include the chat app’s URLs in the main urls.py file:

# chat_app/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('chat/', include('chat.urls')),
]

9. Create HTML and JavaScript for Chat

In the chat/templates/chat/room.html file, create the front end for the chat:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Chat Room</title>
</head>
<body>
    <h1>Chat Room: {{ room_name }}</h1>
    <textarea id="chat-log" cols="100" rows="20" readonly></textarea><br>
    <input id="chat-message-input" type="text" size="100"><br>
    <input id="chat-message-submit" type="button" value="Send">

    <script>
        const roomName = "{{ room_name }}";
        const chatSocket = new WebSocket(
            'ws://' + window.location.host + '/ws/chat/' + roomName + '/'
        );

        chatSocket.onmessage = function(e) {
            const data = JSON.parse(e.data);
            document.querySelector('#chat-log').value += (data.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 key
                document.querySelector('#chat-message-submit').click();
            }
        };

        document.querySelector('#chat-message-submit').onclick = function(e) {
            const messageInputDom = document.querySelector('#chat-message-input');
            const message = messageInputDom.value;
            chatSocket.send(JSON.stringify({
                'message': message
            }));
            messageInputDom.value = '';
        };
    </script>
</body>
</html>

10. Run Redis and Django

Make sure Redis is running, then run the Django development server:

redis-server
python manage.py runserver

11. Testing the Chat Application

You can open multiple browser windows and navigate to different chat rooms by visiting URLs like:

http://127.0.0.1:8000/chat/room_name/

Replace room_name with any name you like to create or join that room. Messages sent from one browser window should appear in all others in the same room in real time.

Conclusion

You have now built a real-time chat application using Django Channels and WebSockets. This implementation supports basic real-time messaging, and you can extend it further with features like user authentication, chat histories, and private messaging.

Leave a Reply

Your email address will not be published. Required fields are marked *