How to Build a Chat Application with Django Channels and WebSocket

In this tutorial, we will learn how to build a real-time chat application using Django Channels and WebSocket. Django Channels is a powerful extension that allows Django to handle WebSockets, HTTP & HTTP2 protocols.

By the end of this tutorial, you will have a working chat application where users can send and receive messages in real-time. Let’s get started!

Prerequisites

To follow along with this tutorial, you will need the following:

  • Python 3.7 or above
  • Django 3.2 or above
  • Django Channels 3.0 or above

If you don’t have Python installed, you can download it from the official Python website: https://www.python.org/downloads/

To install Django and Django Channels, open a terminal or command prompt and run the following commands:

pip install django
pip install channels

Setting up the Django Project

Let’s start by creating a new Django project. Open a terminal and run the following command:

django-admin startproject chatapp

This will create a new directory named chatapp with the basic structure of a Django project.

Change into the project directory:

cd chatapp

Next, create a new Django app within the project. Run the following command:

python manage.py startapp chat

This will create a new directory named chat with the basic structure of a Django app.

Now, let’s add the newly created app to the INSTALLED_APPS list in the settings.py file:

INSTALLED_APPS = [
    # ...
    'chat',
    # ...
]

Creating the Chat Model

We will start by creating a Chat model to represent a chat room. Open the chat/models.py file and add the following code:

from django.db import models

class Chat(models.Model):
    name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)

This model represents a basic chat room with a name and a creation timestamp. We will use this model to store information about individual chat rooms.

Run the following command to create the necessary database tables:

python manage.py migrate

Creating the Chat Room View

Next, let’s create the view that will display the chat room to users. Open the chat/views.py file and add the following code:

from django.shortcuts import render
from django.views.generic import TemplateView
from .models import Chat


class ChatRoomView(TemplateView):
    template_name = 'chat/chat_room.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['chats'] = Chat.objects.all()
        return context

In this code, we are using Django’s TemplateView class to render a template file named chat_room.html. We also fetch all chat rooms from the database and pass them to the template context.

Creating the Chat Room Template

Create a new directory named templates inside the chat directory. Then, create a new file named chat_room.html inside the templates directory.

Open the chat/templates/chat_room.html file and add the following code:

<!DOCTYPE html>
<html>
<head>
    <title>Chat Room</title>
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
    <h1>Chat Room</h1>

    <div id="chats">
        {% for chat in chats %}
            <p>{{ chat.name }}</p>
        {% endfor %}
    </div>

    <form id="chat-form" method="POST">
        {% csrf_token %}
        <input type="text" name="message" id="message" placeholder="Enter a message" />
        <button type="submit">Send</button>
    </form>

    <script type="text/javascript">
        $(document).ready(function() {
            // Establish WebSocket connection
            const socket = new WebSocket('ws://localhost:8000/ws/chat/');

            // Handle incoming WebSocket messages
            socket.onmessage = function(event) {
                const message = JSON.parse(event.data);
                $('#chats').append('<p>' + message.message + '</p>');
            }

            // Handle form submission
            $('#chat-form').on('submit', function(event) {
                event.preventDefault();

                const message = $('#message').val();
                socket.send(JSON.stringify({'message': message}));

                $('#message').val('');
            });
        });
    </script>
</body>
</html>

In this template, we are rendering the list of chat rooms and displaying a form for users to send messages. When the form is submitted, we send the message to the WebSocket server using the socket.send() method.

Creating the WebSocket Consumer

Now, let’s create the WebSocket consumer that will handle WebSocket connections and messages. Create a new directory named consumers inside the chat directory. Then, create a new file named chat_consumer.py inside the consumers directory.

Open the chat/consumers/chat_consumer.py file and add the following code:

from channels.generic.websocket import AsyncWebsocketConsumer


class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.chat_name = self.scope['url_route']['kwargs']['chat_name']
        self.chat_group_name = 'chat_%s' % self.chat_name

        # Join chat room group
        await self.channel_layer.group_add(
            self.chat_group_name,
            self.channel_name
        )

        await self.accept()

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

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

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

    async def chat_message(self, event):
        message = event['message']

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

This ChatConsumer class is a WebSocket consumer that handles the WebSocket connection, disconnection, and incoming messages. When a message is received, it sends the message to the chat room group, which broadcasts it to all connected clients.

Routing WebSocket URLs

To connect Django Channels to the WebSocket protocol, we need to define a routing configuration. Create a new file named routing.py in the project directory.

Open the chatapp/routing.py file and add the following code:

from django.urls import path
from .consumers import ChatConsumer

websocket_urlpatterns = [
    path('ws/chat/<str_chat_name>/', ChatConsumer.as_asgi()),
]

In this code, we define a WebSocket URL pattern that matches the URL ws/chat/<chat_name>/ and maps it to the ChatConsumer class.

Configuring ASGI Application

To enable Django Channels, we need to configure ASGI (Asynchronous Server Gateway Interface) application. Open the chatapp/asgi.py file and update the following code:

import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from chatapp.routing import websocket_urlpatterns

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

application = ProtocolTypeRouter(
    {
        'http': get_asgi_application(),
        'websocket': URLRouter(websocket_urlpatterns)
    }
)

This code sets up the ASGI application to handle both HTTP and WebSocket requests. The URLRouter maps the WebSocket URLs to the appropriate consumers.

Updating the Project URL Configuration

Finally, we need to update the project URL configuration to include the chat app URLs. Open the chatapp/urls.py file and add the following code:

from django.contrib import admin
from django.urls import path, include

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

Running the Development Server

Now that we have finished setting up our chat application, let’s run the development server and test it out. In a terminal, run the following command:

python manage.py runserver

Open your web browser and visit http://localhost:8000/. You should see the chat room with a list of chat rooms and a form to send messages.

Open multiple browser windows or tabs and enter the same chat room. Send a message from one window, and you should see the message appear in real-time on all connected windows.

Congratulations! You have successfully built a chat application with Django Channels and WebSocket. Feel free to explore and extend the application further. You can add authentication, implement private messaging, or enhance the user interface.

Conclusion

In this tutorial, we learned how to build a real-time chat application using Django Channels and WebSocket. We covered the steps to set up the project, create the chat model, implement the chat room view and template, create the WebSocket consumer, configure the routing, and run the development server.

By using Django Channels and WebSocket, we were able to create a chat application that enables real-time communication between multiple users. This is just the beginning. You can expand on this application by adding more features to meet your specific requirements.

I hope this tutorial has been helpful in understanding how to build a chat application with Django Channels and WebSocket. Enjoy coding and building real-time applications with Django!

Related Post