Building Real-Time Features with Django, HTMX & WebSockets

July 28, 2026 · Ahmad M. Waddah · 42 reads

⚡ Stack: Django · HTMX · WebSockets · PostgreSQL · Docker


❓ The Problem

Social platforms need real-time updates — new posts, likes, comments, notifications. Traditionally this means either:

  1. Polling — clients hammer the server every N seconds (wasteful, slow)
  2. SPA + WebSockets — React/Vue + Socket.io (heavy, complex tooling)

Neither fits a Django project that values simplicity and server-rendered HTML.


🛠️ The Approach

1. Django Channels for WebSocket Handling

# consumers.py
class NotificationConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.user = self.scope["user"]
        if self.user.is_authenticated:
            await self.channel_layer.group_add(
                f"user_{self.user.id}", self.channel_name
            )
            await self.accept()

Channels sits alongside your existing Django app — no need to rewrite anything. It handles the WebSocket lifecycle and message routing.

2. HTMX for DOM Updates

The magic is that HTMX swaps HTML, not JSON. When a new post arrives via WebSocket:

<div hx-ext="ws" ws-connect="/ws/feed/">
    <div id="feed-stream">
        {% for post in posts %}
            {% include "feed/_post.html" %}
        {% endfor %}
    </div>
</div>

A server-sent message triggers hx-swap on #feed-stream — prepending the new post HTML. No client-side templates, no state management, no re-rendering.

3. Triggering from Django ORM

# signals.py
@receiver(post_save, sender=Post)
async def notify_followers(sender, instance, created, **kwargs):
    if created:
        await async_to_sync(channel_layer.group_send)(
            f"user_feed_{instance.author.id}",
            {
                "type": "feed.update",
                "html": render_post_partial(instance),
            },
        )

📈 Results

Metric Before (polling) After (WebSocket + HTMX)
Requests/sec 42 3
Avg latency 1200ms 180ms
Bandwidth 2.3 MB/min 120 KB/min

💡 Key Takeaways

  • HTMX + WebSockets let you keep Django's templating system end-to-end
  • Channel layers (Redis) scale horizontally — one process per core
  • No frontend framework = faster iterations, smaller bundle, easier debugging
  • The async_to_sync bridge lets ORM signals push to WebSocket groups seamlessly

🔗 For a deeper look, check out the Pulse Feed project.