Real-Time Chat Feature with Django Channels, Redis & DRF

Backend Workflow: Message Journey Through Django Channels
**Complete Flow Diagram**
=========================
USER SENDS MESSAGE
↓
[1] WebSocket sends: '{"message": "Hello"}'
↓
[2] routing.py → routes to ChatConsumer
↓
[3] consumers.py → receive() method
↓
├─→ [4] save_message()
│ ↓
│ Database INSERT
│ (Message stored permanently)
│
└─→ [5] channel_layer.group_send()
↓
[6] Channel Layer (InMemory/Redis)
↓
Broadcasts to ALL consumers in group 'chat_1'
↓
┌──────────┬──────────┬──────────┐
↓ ↓ ↓ ↓
Consumer A Consumer B Consumer C Consumer D
↓ ↓ ↓ ↓
[7] chat_message() method called on each
↓ ↓ ↓ ↓
[8] send() to WebSocket
↓ ↓ ↓ ↓
User A User B User C User D
receives receives receives receives
Step 1: Install Required Packages
pip install channels channels-redis daphne redis
Step 2: Update Django Settings
INSTALLED_APPS = [
'channels',
]
ASGI_APPLICATION = 'your_project.asgi.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
Step 3: Configure ASGI (project/asgi.py)
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'app.settings')
django_asgi_app = get_asgi_application()
from chats.routing import websocket_urlpatterns
application = ProtocolTypeRouter({
"http": django_asgi_app,
"websocket": AuthMiddlewareStack(URLRouter(websocket_urlpatterns)),
})
Step-4: Create Chat Models (app/models.py)
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Room(models.Model):
name = models.CharField(max_length=255, null=True, blank=True)
participants = models.ManyToManyField(User, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Message(models.Model):
room = models.ForeignKey(Room, on_delete=models.CASCADE, related_name='messages', null=True, blank=True)
sender = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
content = models.TextField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['created_at']
Step-5: Run Migrations
python manage.py makemigrations
python manage.py migrate
Step-6: Create WebSocket Consumer(app/consumers.py)
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from .models import Room, Message
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_id = self.scope['url_route']['kwargs']['room_id']
self.room_group = f'chat_{self.room_id}'
await self.channel_layer.group_add(self.room_group, self.channel_name)
await self.accept()
async def disconnect(self, code):
await self.channel_layer.group_discard(self.room_group, self.channel_name)
async def receive(self, text_data):
data = json.loads(text_data)
message = data['message']
user = self.scope['user']
await self.save_message(user, message)
username = user.username if user.is_authenticated else 'Anonymous'
await self.channel_layer.group_send(
self.room_group,
{
'type': 'chat_message',
'message': message,
'username': username,
}
)
async def chat_message(self, event):
await self.send(text_data=json.dumps({
'message': event['message'],
'username': event['username'],
}))
@database_sync_to_async
def save_message(self, user, content):
from django.contrib.auth import get_user_model
User = get_user_model()
room = Room.objects.get(id=self.room_id)
if user.is_authenticated:
actual_user = User.objects.get(id=user.id)
else:
return None
return Message.objects.create(
room=room,
sender=actual_user,
content=content
)
Step-7: WebSocket Routing (chat/routing.py)
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path('ws/chat/<int:room_id>/', consumers.ChatConsumer.as_asgi()),
]
Step 8: REST API (chat/serializers.py)
from rest_framework import serializers
from .models import Room, Message
class MessageSerializer(serializers.ModelSerializer):
sender = serializers.StringRelatedField()
class Meta:
model = Message
fields = ['id', 'sender', 'content', 'created_at']
class RoomSerializer(serializers.ModelSerializer):
class Meta:
model = Room
fields = ['id', 'name', 'created_at']
Step 9: REST API Views (chat/views.py)
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Room, Message
from .serializers import RoomSerializer, MessageSerializer
class RoomViewSet(viewsets.ModelViewSet):
queryset = Room.objects.all()
serializer_class = RoomSerializer
@action(detail=True, methods=['get'])
def messages(self, request, pk=None):
room = self.get_object()
messages = room.messages.all()
serializer = MessageSerializer(messages, many=True)
return Response(serializer.data)
Step 10: HTTP URLs (chat/urls.py)
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import RoomViewSet
router = DefaultRouter()
router.register('rooms', RoomViewSet)
urlpatterns = [
path('', include(router.urls)),
]
Main urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/chat/', include('chat.urls')),
]
API Documentation
Base Url
HTTP: http://localhost:8000/api/chat/
WebSocket: ws://localhost:8000/ws/chat/
📡 REST API Endpoints
1. List All Chat Rooms
GET /api/chat/rooms/
Get all chat rooms.
Request:
GET /api/chat/rooms/
Content-Type: application/json
Response (200 OK):
[
{
"id": 1,
"name": "General Chat",
"created_at": "2025-11-23T10:00:00Z"
},
{
"id": 2,
"name": "Project Discussion",
"created_at": "2025-11-23T11:30:00Z"
}
]
cURL Example:
curl http://localhost:8000/api/chat/rooms/
2. Get Single Chat Room
GET /api/chat/rooms/{id}/
Get details of a specific room.
Request:
GET /api/chat/rooms/1/
Content-Type: application/json
Response (200 OK):
{
"id": 1,
"name": "General Chat",
"created_at": "2025-11-23T10:00:00Z"
}
Response (404 Not Found):
{
"detail": "Not found."
}
cURL Example:
curl http://localhost:8000/api/chat/rooms/1/
3. Create New Chat Room
POST /api/chat/rooms/
Create a new chat room.
Request:
POST /api/chat/rooms/
Content-Type: application/json
{
"name": "Marketing Team"
}
Response (201 Created):
{
"id": 3,
"name": "Marketing Team",
"created_at": "2025-11-23T12:00:00Z"
}
Response (400 Bad Request):
{
"name": [
"This field is required."
]
}
cURL Example:
curl -X POST http://localhost:8000/api/chat/rooms/ \
-H "Content-Type: application/json" \
-d '{"name": "Marketing Team"}'
4. Update Chat Room
PUT /api/chat/rooms/{id}/
PATCH /api/chat/rooms/{id}/
Update an existing chat room.
Request (PATCH - Partial Update):
PATCH /api/chat/rooms/1/
Content-Type: application/json
{
"name": "Updated Room Name"
}
Response (200 OK):
{
"id": 1,
"name": "Updated Room Name",
"created_at": "2025-11-23T10:00:00Z"
}
cURL Example:
curl -X PATCH http://localhost:8000/api/chat/rooms/1/ \
-H "Content-Type: application/json" \
-d '{"name": "Updated Room Name"}'
5. Delete Chat Room
DELETE /api/chat/rooms/{id}/
Delete a chat room and all its messages.
Request:
DELETE /api/chat/rooms/1/
Response (204 No Content):
(Empty response body)
cURL Example:
curl -X DELETE http://localhost:8000/api/chat/rooms/1/
6. Get Messages in a Room
GET /api/chat/rooms/{id}/messages/
Get all messages in a specific chat room.
Request:
GET /api/chat/rooms/1/messages/
Content-Type: application/json
Response (200 OK):
[
{
"id": 1,
"sender": "john_doe",
"content": "Hello everyone!",
"created_at": "2025-11-23T10:05:00Z"
},
{
"id": 2,
"sender": "jane_smith",
"content": "Hi John! Welcome to the chat.",
"created_at": "2025-11-23T10:06:30Z"
},
{
"id": 3,
"sender": "john_doe",
"content": "Thanks! Happy to be here.",
"created_at": "2025-11-23T10:07:15Z"
}
]
Response (Empty Room - 200 OK):
[]
cURL Example:
curl http://localhost:8000/api/chat/rooms/1/messages/
