pythondjangoreal-timewebsocketsdjango-channels

Getting Started with WebSockets in Django

0 likes 17 views 5 mins read
lordson

WebSockets have become an essential tool for building real-time web applications. Whether you're building a chat app, live notifications, or a collaborative tool, WebSockets allow your server and client to communicate instantly without the overhead of repeated HTTP requests. In this guide, we'll walk through how to set up WebSockets in Django using Django Channels.

What Are WebSockets?

HTTP is a request-response protocol — the client asks, the server answers, and the connection closes. This works fine for most web interactions, but falls apart when you need real-time communication. Imagine a chat app where you have to refresh the page to see new messages — that's the HTTP way.

WebSockets solve this by keeping a persistent, two-way connection open between the client and server. Once the connection is established, both sides can send messages to each other at any time, making it perfect for real-time features.

Prerequisites

Before we dive in, make sure you have the following installed:

  • Python 3.10+
  • Django 4.x+
  • Redis (for the channel layer)

Setting Up Django Channels

Django doesn't support WebSockets out of the box. Django Channels extends Django to handle WebSockets, HTTP2, and other protocols alongside standard HTTP.

Start by installing the required packages:

pip install channels channels-redis daphne

Next, add Channels to your installed apps:

 
# settings.py
INSTALLED_APPS = [
    'daphne',  # must be first
    'django.contrib.auth',
    # ... rest of your apps
    'channels',
]

Then configure the ASGI application:

# settings.py
ASGI_APPLICATION = 'myproject.asgi.application'

Configuring the Channel Layer

The channel layer allows different parts of your application to communicate with each other. We'll use Redis as the backend:

 
settings.py
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            'hosts': [('127.0.0.1', 6379)],
        },
    },
}

Make sure Redis is running locally:

sudo service redis-server start

Setting Up the ASGI Application

Replace the contents of your asgi.py file:

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

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

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

Writing a Consumer

A consumer is the Channels equivalent of a Django view — it handles WebSocket connections. Let's write a simple chat consumer:

# myapp/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
        )

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

        # broadcast message to room group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message,
            }
        )

    async def chat_message(self, event):
        # send message to WebSocket
        await self.send(text_data=json.dumps({
            'message': event['message']
        }))

Routing

Wire up the consumer to a URL:

# myapp/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()),
]

Connecting from React

On the frontend, the native WebSocket API is all you need:

// hooks/useWebSocket.js
import { useEffect, useRef, useState } from 'react'

export const useWebSocket = (roomName) => {
  const [messages, setMessages] = useState([])
  const ws = useRef(null)

  useEffect(() => {
    ws.current = new WebSocket(`ws://localhost:8000/ws/chat/${roomName}/`)

    ws.current.onopen = () => console.log('Connected')

    ws.current.onmessage = (e) => {
      const data = JSON.parse(e.data)
      setMessages(prev => [...prev, data.message])
    }

    ws.current.onclose = () => console.log('Disconnected')

    return () => ws.current.close()
  }, [roomName])

  const sendMessage = (message) => {
    if (ws.current.readyState === WebSocket.OPEN) {
      ws.current.send(JSON.stringify({ message }))
    }
  }

  return { messages, sendMessage }
}
// ChatRoom.jsx
const ChatRoom = ({ roomName }) => {
  const { messages, sendMessage } = useWebSocket(roomName)
  const [input, setInput] = useState('')

  const handleSend = () => {
    if (!input.trim()) return
    sendMessage(input)
    setInput('')
  }

  return (
    <div>
      <div className="messages">
        {messages.map((msg, i) => (
          <p key={i}>{msg}</p>
        ))}
      </div>
      <input value={input} onChange={e => setInput(e.target.value)} />
      <button onClick={handleSend}>Send</button>
    </div>
  )
}

Running the Server

Django Channels uses Daphne instead of the standard runserver:

daphne -p 8000 myproject.asgi:application

Or during development you can still use:

python manage.py runserver

Channels patches the development server automatically when Daphne is in INSTALLED_APPS.

What to Build Next

Now that you have the foundation, here are some directions to take it further. You could add authentication to your consumers using self.scope['user'] to identify who is sending messages. You could also persist messages to the database using Django ORM inside the consumer — just make sure to use database_sync_to_async when making synchronous ORM calls from an async consumer. For production, swap out the local Redis instance for a managed Redis service like Redis Cloud or AWS ElastiCache, and deploy using Daphne behind Nginx with WebSocket proxy support configured.

Conclusion

Django Channels bridges the gap between Django's synchronous nature and the real-time web. With just a few configuration steps and a consumer, you have a fully functional WebSocket server capable of powering chat apps, live notifications, collaborative editors, and more. The combination of Django Channels on the backend and the native WebSocket API on the frontend gives you a clean, scalable foundation to build on.

logo image
© 2021-2026 • Django Cameroon • All rights reserved Terms of use & Privacy Policy
SitemapCreditsFAQs