Revolutionize Your Chat App with Django Channels: Unleashing Real-Time Communication Power!
Check out my previous blog about Create A Hello World! Application Using Django Framework.
Introduction
Django Channels, an extension to Django, empowers developers to build real-time applications with ease. In this step-by-step guide, We will explore how to leverage Django Channels to create a chat application that revolutionizes communication.
Get ready to take your chat app to the next level!
Prerequisites
Before diving into this tutorial, ensure that you have the following prerequisites in place:
Basic understanding of Python and Django Framework.
Python (version 3.6 or above) and pip installed on your system.
Familiarity with the Django framework and its concepts.
[Note: Use Virtual Environment For Good. 👍 ]
Steps
1. Setup and Installation
To get started, follow these steps to set up the Django framework:
Install Django Framework using pip:
pip install django
Create a new Django project:
django-admin startproject myproject
Create a new Django app within your project:
cd myproject
python manage.py startapp myapp
2. Installation and Config of Channels
I. Installation of channels
Channels are available on PyPI — to install it run:
pip install -U channels["daphne"]
Check out the Best Channels Documentation.
II. Configuration of settings.py
Open myproject/settings.py
and update the below:
INSTALLED_APPS = [
# 👇 1. Add the below line
"daphne",
'django.contrib.admin',
# ....
# ...
# ..
# .
'myapp',
]
TEMPLATES = [
{
# 👇 2. Add the below line for templates
'DIRS': ['templates'],
# ....
# ...
# ..
# .
},
]
# 👇 3. Comment the below line
# WSGI_APPLICATION = 'myproject.wsgi.application'
# 👇 4. Add the below line for asgi config
ASGI_APPLICATION = 'myproject.asgi.application'
# 👇 5. Add the below line for channel layer
CHANNEL_LAYERS = {
'default': {
'BACKEND': "channels.layers.InMemoryChannelLayer"
}
}
I. INSTALLED_APPS:
The
INSTALLED_APPS
variable in Django's settings.py file lists all the Django applications installed in your project.By adding
"daphne"
to theINSTALLED_APPS
, you are including the Daphne ASGI server as part of your project. Daphne is a high-performance ASGI server that Django Channels can use to handle WebSocket connections.
II. TEMPLATES:
The
TEMPLATES
variable in settings.py defines a list of dictionaries containing options for Django's template engine.By adding
DIRS
to the first dictionary, you specify the directories where Django should look for template files.In this case,
['templates']
indicates that Django should search for template files in a directory called "templates" within your project.
III. WSGI_APPLICATION:
The
WSGI_APPLICATION
setting specifies the WSGI application that Django uses to handle HTTP requests.By commenting out the line (
# WSGI_APPLICATION = 'myproject.wsgi.application'
), you are disabling the default WSGI application configuration.
IV. ASGI_APPLICATION:
The
ASGI_APPLICATION
setting specifies the ASGI application that Django uses to handle WebSocket connections and other asynchronous operations.By adding
ASGI_APPLICATION = 'myproject.asgi.application'
, you are pointing Django to the ASGI application located in the "core" directory with the filename "asgi.py".
V. CHANNEL_LAYERS:
The
CHANNEL_LAYERS
setting configures the communication layer used by Django Channels for WebSocket handling.By defining
'BACKEND': "channels.layers.InMemoryChannelLayer"
under the'default'
key, you are using the in-memory channel layer provided by Django Channels for development purposes.In production, you would typically use a more robust channel layer backend, such as Redis or RabbitMQ.*
These configuration changes are necessary for integrating Django Channels into your project and enabling real-time communication through WebSocket connections.
III. Configuration of asgi.py
Open myproject/asgi.py
and update the below:
import os
# 👇 1. Update the below import lib
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from myapp.routing import websocket_urlpatterns
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
# 👇 2. Update the application var
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AllowedHostsOriginValidator(
URLRouter(
websocket_urlpatterns
)
),
})
I. Importing Libraries:
The
import os
statement imports theos
module, which provides a way to interact with the operating system.The updated line (
from django.core.asgi import get_asgi_application
) imports theget_asgi_application
function from thedjango.core.asgi
module. This function returns the ASGI application object for your Django project.
II. Setting the Django Settings Module:
The line
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
sets the environment variableDJANGO_SETTINGS_MODULE
to specify the location of your Django project's settings.In this example, it is set to
'myproject.settings'
, assuming your project's settings module is located in themyproject
directory.
III. Defining the application
Variable:
The
application
variable is a key component in the ASGI (Asynchronous Server Gateway Interface) setup.The
ProtocolTypeRouter
class from thechannels.routing
module is used to define a dictionary-based protocol router that routes different protocols to appropriate applications.
In this case, the router is defined with two keys:
"http"
: The HTTP protocol is routed to theget_asgi_application()
function, which returns the ASGI application object for handling HTTP requests."websocket"
: The WebSocket protocol is routed to theAllowedHostsOriginValidator
, which is used for validating the origin of incoming WebSocket connections. It wraps theURLRouter
and allows connections from allowed hosts.The
URLRouter
is initialized withwebsocket_urlpatterns
imported from themyapp.routing
module. This variable contains the URL patterns for WebSocket connections in your application.
These changes are made in the asgi.py
file of your Django project and help configure the ASGI application to handle HTTP requests and WebSocket connections using Django Channels.
Now, let’s dive into the steps required to create a chat application using Django Channels.
3. Setting up URLs and Templates
To configure the URLs and templates in your Django project, follow these steps:
I. URL Configuration:
Open the myproject/urls.py
and write the below code:
from django.contrib import admin
from django.urls import path, include # 👈 1. Add this line
urlpatterns = [
path('admin/', admin.site.urls),
# 👇 2. Add the app url on this
path('', include('myapp.urls'))
]
II. URL Configuration of views:
Create a new file urls.py
inside the myapp
folder and write the below code:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index')
]
III. Added views logic:
Open the views.py
file from myapp
folder and write the below code for redirecting the request to an index.html
template:
from django.shortcuts import render
# Create your views here.
def index(request):
return render(request, 'index.html')
IV. Template Configuration:
Create a folder named templates
inside the myproject
folder:
Now, open templates
and create a new file base.html
and write the below code:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Custom block for page title -->
<title>{% block title %}{% endblock %} | Welcome Room</title>
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<!-- Custom block for content of body -->
{% block content %}{% endblock %}
<!-- Bootstrap 5 JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
<!-- Custom block for javascript -->
{% block js_script %}{% endblock %}
</body>
</html>
Now, Again create a new file index.html
inside the templates
folder:
{% extends 'base.html' %}
{% block title %} Home {% endblock %}
{% block content %}
<div class="container mt-5">
<h3>Welcome to Room</h3>
<div class="row">
<div class="col-lg-4">
<div class="w-100">
<div class="mb-3">
<label for="textMessage" class="form-label">Enter your message:</label>
<input type="text" class="form-control" id="textMessage">
</div>
<button id="addMessage" class="btn btn-primary rounded-1">Send</button>
</div>
</div>
<div class="col-lg-8">
<div id="messages" class="mt-4"></div>
</div>
</div>
</div>
{% endblock %}
{% block js_script %}
<script>
// setup chat scoket
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/chat/public_room/'
);
// on socket open
chatSocket.onopen = function (e) {
console.log('Chat socket successfully connected.');
};
// on socket close
chatSocket.onclose = function (e) {
console.log('Chat socket closed unexpectedly');
};
// on receiving message on group
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
const message = data.message;
setMessage(message);
};
// sending the text message to server
document.querySelector('#addMessage').onclick = function(e) {
const messageInputDom = document.querySelector('#textMessage');
const message = messageInputDom.value;
chatSocket.send(JSON.stringify({
'message': message
}));
messageInputDom.value = '';
};
// helper func setting message
function setMessage(message){
var div = document.createElement('div');
div.className = 'alert alert-success alert-dismissible fade show';
div.setAttribute('role', 'alert');
var message = document.createTextNode(message);
div.appendChild(message);
var closeButton = document.createElement('button');
closeButton.type = 'button';
closeButton.className = 'btn-close';
closeButton.setAttribute('data-bs-dismiss', 'alert');
closeButton.setAttribute('aria-label', 'Close');
div.appendChild(closeButton);
var container = document.getElementById('messages');
container.appendChild(div);
}
</script>
{% endblock %}
The provided code represents an HTML structure for a chat room interface. Let’s go through each element:
<div class=”container mt-5">
: This div serves as a container for the chat room interface. Thecontainer
class provides a fixed-width container andmt-5
adds a margin-top to create some spacing.<h3>Welcome to Room</h3>
: This heading(h3)
displays the welcome message or title for the chat room.<div class=”row”>
: This div defines a row to contain two columns.<div class=”col-lg-4">
: This div represents the left column in the row. It occupies 4 columns on large screens(col-lg-4 class)
. Adjust the class based on your layout requirements.<div class=”w-100">
: This div provides a full-width container within the column.<div class=”mb-3">
: This div adds some margin-bottom to create spacing.<label for=”textMessage” class=”form-label”> Enter your message:</label>
: This label element displays the text “Enter your message:” and is associated with the input field below.<input type=”text” class=”form-control” id=”textMessage”>:
This input element is a text input field where users can enter their messages. Theform-control
class is used for styling purposes, and theid
attribute provides an identifier for JavaScript manipulation.<button id=”addMessage” class=”btn btn-primary rounded-1">Send</button>
: This button element represents a “Send” button. It has thebtn
andbtn-primary
classes for styling and therounded-1
class to apply rounded corners. Theid
attribute is used for JavaScript manipulation.<div class=”col-lg-8">
: This div represents the right column in the row. It occupies 8 columns on large screens (col-lg-8
class). Adjust the class based on your layout requirements.<div id=”messages” class=”mt-4"></div>
: This div serves as a container for displaying the messages. Theid
attribute is used for JavaScript manipulation, and themt-4
class adds a margin-top to create spacing.
Overall, this HTML code creates a chat room interface with a welcome message, an input field for entering messages, a “Send” button, and a container for displaying the messages. The layout is structured using Bootstrap’s grid system with columns and rows.
The provided code is a JavaScript script that handles the functionality of the chat room interface. Let’s break it down:
const chatSocket = new WebSocket('ws://' +
window.location.host
+ '/ws/chat/public_room/');
: This line creates a WebSocket connection by instantiating aWebSocket
object. It uses the URL'ws://' +
window.location.host
+ '/ws/chat/public_room/'
to connect to the WebSocket server. Thewindow.location.host
retrieves the current host, and/ws/chat/public_room/
represents the endpoint or URL path for the chat room WebSocket.chatSocket.onopen
: This event listener is triggered when the WebSocket connection is successfully opened. It logs a message to the console, indicating that the chat socket is successfully connected.chatSocket.onclose
: This event listener is triggered when the WebSocket connection is closed. It logs a message to the console, indicating that the chat socket was closed unexpectedly.chatSocket.onmessage
: This event listener is triggered when a message is received from the WebSocket server. It parses the received data into a JavaScript object usingJSON.parse()
, extracts themessage
property from the data, and calls thesetMessage()
function, passing the message as an argument.document.querySelector('#addMessage').onclick
: This event listener is triggered when the "Send" button with the idaddMessage
is clicked. It retrieves the value of the input field with the idtextMessage
, constructs a message object with themessage
property set to the input value, sends the message to the WebSocket server usingchatSocket.send()
, clears the input field, and performs any necessary updates.function setMessage(message)
: This function is a helper function that sets the message in the chat interface. It creates adiv
element with the classesalert
,alert-success
,alert-dismissible
, andfade show
for styling purposes. It also appends a text node containing the message text to thediv
element. Additionally, it creates a close button (button
element) with the classesbtn-close
and attributesdata-bs-dismiss
andaria-label
for closing the alert. Finally, it retrieves the container element with the idmessages
and appends the createddiv
element to it.
Overall, this JavaScript code sets up a WebSocket connection, handles events such as socket opening, socket close, and message reception, sends messages to the server, and updates the chat interface with received messages.
4. Define routing for WebSocket connections:
WebSocket connection routing in Django Channels is the process of mapping WebSocket URLs to their corresponding consumers. When a client establishes a WebSocket connection to a specific URL, the routing mechanism determines which consumer should handle the connection.
For routing of WebSocket connections is defined in a routing.py
file within the project directory.
Now, Create a new file routing.py
file inside the myapp
folder and write the below code:
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r"ws/chat/public_room/", consumers.ChatConsumer.as_asgi()),
]
The
django.urls
the module is imported to access thepath
function, which is used for defining URL patterns.The
ChatConsumer
class (imported from the.consumers
module) is the consumer that handles WebSocket connections for the chat functionality.websocket_urlpatterns
is a list that contains URL patterns for WebSocket connections. Each pattern specifies a URL that begins withws/chat/public_room
.The
path
the function is used to define the URL pattern for WebSocket connections. It takes two arguments: the URL pattern itself and the consumer that will handle the connection.ChatConsumer.as
_asgi()
is passed as the second argument to thepath
function. This converts theChatConsumer
class into an ASGI application that can handle WebSocket connections.
To summarize, the code defines a URL pattern for WebSocket connections to the /ws/chat/public_room/
URL. When a client establishes a WebSocket connection to this URL, the ChatConsumer
consumer is invoked to handle the connection.
5. Consumers for WebSocket connections:
In Django Channels, a consumer is a class that handles WebSocket connections and manages the communication between the server and the connected clients. Consumers are the building blocks of real-time applications built with Django Channels.
Create a new file consumers.py
inside the myapp
folder and write the below code:
import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
class ChatConsumer(WebsocketConsumer):
def connect(self):
self.room_name = 'public_room'
self.room_group_name = self.room_name
# Join room group
async_to_sync(self.channel_layer.group_add)(
self.room_group_name, self.channel_name
)
self.accept()
def disconnect(self, code):
# Leave room group
async_to_sync(self.channel_layer.group_discard)(
self.room_group_name, self.channel_name
)
def receive(self, text_data):
json_text = json.loads(text_data)
message = json_text["message"]
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
"type": "chat_message",
"message": message
}
)
def chat_message(self, event):
message = event['message']
# Send message to WebSocket
self.send(text_data=json.dumps({"message": message}))
In the code, the ChatConsumer
class is a subclass of WebsocketConsumer
, which is a generic implementation of a consumer provided by Django Channels. Let's break down the code and understand its functionality:
I. connect():
This method is called when a WebSocket connection is established.
The
room_name
androom_group_name
variables are initialized to identify the chat room.The consumer joins the specified
room_group_name
by adding itself to the group usingasync_to_sync(
self.channel
_
layer.group
_add)
.Finally,
self.accept()
is called to accept the WebSocket connection.
II. disconnect():
This method is called when the WebSocket connection is closed or disconnected.
The consumer leaves the
room_group_name
by removing himself from the group usingasync_to_sync(
self.channel
_
layer.group
_discard)
.
III. receive(text_data):
This method is called when the server receives data from the WebSocket connection.
The received
text_data
is parsed as JSON, extracting themessage
value.The consumer sends the received message to the entire
room_group_name
by usingasync_to_sync(
self.channel
_
layer.group
_send)
.
IV. chat_message(event):
This method is responsible for handling messages sent from the
room_group_name
to the WebSocket connection.It extracts the
message
from the event dictionary.The consumer sends the message back to the WebSocket connection by calling
self.send()
.
The consumer plays a crucial role in Django Channels as it manages the connection, handles incoming messages, and broadcasts messages to the relevant recipients. It provides an interface for handling events, such as connecting, disconnecting, and receiving messages, in a WebSocket-based application.
By implementing a consumer, you can define the desired behavior of your application’s WebSocket connections, enabling real-time communication and interaction between the server and connected clients.
6. Testing and Running
Now that we have set up the basic structure of our chat application using Django Channels, it’s time to test and run the app. Follow these steps:
Step 1: Open your Command-Line Interface:
Open your command-line interface and navigate to the root directory of your Django project.
To proceed, please open the terminal within the myproject
folder and execute the following command:
python manage.py makemigrations
python manage.py migrate
Step 2: Start the Server:
To start the server, run the following command in your command-line interface:
python manage.py runserver
This command will launch the Django development server.
Step 3: Testing
After running the server and accessing the project interface at http://127.0.0.1:8000/
.
Open any browser and hit : http://127.0.0.1:8000/
url and you can the home page of our website looks like this:
Now, Open a new tab in another browser and hit the same url and open both tab side by side like this:
Now, with the implementation of Django Channels in our chat application, the power of real-time communication comes to life. When you send a message from one side of the chat room, it instantly appears on both sides, providing a seamless and immersive experience. This dynamic functionality fulfills our goal of fostering communication in a public room.
Imagine the possibilities! Users can engage in vibrant discussions, share ideas, and connect with others in real-time. Whether it’s a collaborative project, an online community, or a customer support channel, our chat app powered by Django Channels ensures that every message sent is received and displayed without delay, enabling smooth and interactive conversations.
Final Result,
Checkout Full Live Demo:
Now, with the implementation of Django Channels in our chat application, the power of real-time communication comes to life. When you send a message from one side of the chat room, it instantly appears on both sides, providing a seamless and immersive experience. This dynamic functionality fulfills our goal of fostering communication in a public room.
Imagine the possibilities! Users can engage in vibrant discussions, share ideas, and connect with others in real time. Whether it’s a collaborative project, an online community, or a customer support channel, our chat app powered by Django Channels ensures that every message sent is received and displayed without delay, enabling smooth and interactive conversations.
Conclusion
Congratulations! You have successfully created a chat application using Django Channels. This tutorial provided an overview of Django Channels integration into a Django project and walked you through the steps required to set up real-time communication. With Django Channels, you can expand the functionality of your chat app and bring an immersive, real-time experience to your users.
Remember to explore more features offered by Django Channels, such as handling multiple chat rooms, authentication, and message persistence, to enhance your application further.
Now, it’s time to unleash the power of Django Channels and take your chat app to new heights.
Happy Coding!
Support my passion for sharing development knowledge by making a donation to Buy Me a Coffee. Your contribution helps me create valuable content and resources. Thank you for your support!
Thank you for taking the time to read this blog about Revolutionize Your Chat App with Django Channels: Unleashing Real-Time Communication Power. I hope that you found the information presented here useful and informative.
If you have any questions or comments about the information presented in this blog, please feel free to reach out. Thank you again for reading!