Django Channels allows Django to handle multiple types of connections beyond the traditional HTTP requests. It uses an event - driven architecture and is built on top of the asgiref
library, which provides an interface for ASGI (Asynchronous Server Gateway Interface).
ASGI is a standard interface between web servers, frameworks, and applications that allows for asynchronous handling of requests. It is an evolution of the WSGI (Web Server Gateway Interface) used by traditional Django applications. With ASGI, Django can handle WebSocket connections, which are the foundation of real - time chat applications.
Channels Layers are used to communicate between different instances of the application. In a chat application, they enable messages sent by one user to be broadcast to other users in the same chat room. Channels Layers can use different backends such as Redis, which is a popular choice for its performance and ease of use.
python3 -m venv myenv
source myenv/bin/activate
pip install django channels
pip install redis
django - admin startproject chat_project
cd chat_project
python manage.py startapp chat_app
settings.py
in your project:# chat_project/settings.py
INSTALLED_APPS = [
#...
'channels',
'chat_app',
]
# Channels
ASGI_APPLICATION = 'chat_project.asgi.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
asgi.py
in your project:# chat_project/asgi.py
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'chat_project.settings')
application = ProtocolTypeRouter({
"http": get_asgi_application(),
# Later we will add WebSocket protocol handling here
})
Create a routing.py
file in your chat_app
:
# chat_app/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()),
]
Update asgi.py
in your project to include the WebSocket routing:
# chat_project/asgi.py
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from chat_app.routing import websocket_urlpatterns
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'chat_project.settings')
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": URLRouter(websocket_urlpatterns)
})
Create a consumers.py
file in your chat_app
:
# chat_app/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 = 'chat_%s' % 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
}))
Create a templates
directory in your chat_app
and inside it, create a chat.html
file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF - 8">
<title>Chat Room</title>
</head>
<body>
<textarea id="chat - log" cols="100" rows="20"></textarea><br>
<input id="chat - message - input" type="text" size="100"><br>
<input id="chat - message - submit" type="button" value="Send">
<script>
var roomName = "{{ room_name }}";
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'];
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>
</body>
</html>
Create a view in views.py
to render the chat page:
# chat_app/views.py
from django.shortcuts import render
def chat_room(request, room_name):
return render(request, 'chat.html', {
'room_name': room_name
})
Update urls.py
in your chat_app
:
# chat_app/urls.py
from django.urls import path
from .views import chat_room
urlpatterns = [
path('<str:room_name>/', chat_room, name='chat_room'),
]
And include the chat_app
URLs in your project’s urls.py
:
# chat_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('chat/', include('chat_app.urls')),
]
CHANNEL_LAYERS
configuration can lead to messages not being broadcast correctly.Building a chat application with Django Channels allows you to leverage the power of Django while adding real - time communication capabilities to your web application. By understanding the core concepts, setting up the project correctly, and following best practices, you can build a robust and scalable chat application. However, be aware of the common pitfalls and take necessary precautions to ensure the security and reliability of your application.