The simplest way to add server sent events to Django 🏺

Photo of Tom Dekan
by Tom Dekan

Adding server sent events to your Django app is simple and powerful. It allows you to push updates to your frontend without the frontend needing to send requests, such as polling.

I'll show you the simplest way (with the least code) to add server sent events to your Django app.

We'll use Daphne. This is a production ASGI server that hooks into Django (relevant Django docs here) and its existing runserver command.

The final product will look like the below. All data is being sent from the server to the frontend in real-time, without the frontend needing to send requests.



Optional video tutorial (featuring me) below 📽️:


Let's start! 🏺

1. Setup app and connect Daphne

  • Create a new Django project and app:
pip install django daphne
django-admin startproject core .
python manage.py startapp sim

Note: Make sure to use >=Django 4.2 . Otherwise, you will get errors like TypeError: async_generator object is not iterable when using async views. (Thanks to Daniel for pointing this out in the Youtube comments)

  • Add 'daphne' to INSTALLED_APPS in core/settings.py as the first app. This allows Daphne to hook into Django's runserver command.
  • Add 'sim' to INSTALLED_APPS in core/settings.py (anywhere in the list).
INSTALLED_APPS = [
    'daphne',
    # ...,
    'sim',
    # ...
]
  • Add the following line to core/settings.py:
ASGI_APPLICATION = "core.asgi.application"

2. Add your views

  • Add the following views to sim/views.py:
import asyncio
import random

from django.http import StreamingHttpResponse
from django.shortcuts import render


async def sse_stream(request):
    """
    Sends server-sent events to the client.
    """
    async def event_stream():
        emojis = ["🚀", "🐎", "🌅", "🦾", "🍇"]
        i = 0
        while True:
            yield f'data: {random.choice(emojis)} {i}\n\n'
            i += 1
            await asyncio.sleep(1)

    return StreamingHttpResponse(event_stream(), content_type='text/event-stream')


def index(request):
    return render(request, 'sse.html')

3. Add URLs

  • Add a URL pattern for the view by adding a urls.py file to sim with the following content:
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('stream/', views.sse_stream, name='sse_stream'),
]
  • Update the URL configuration in core/urls.py:
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('sim.urls')),
]

4. Add your templates

  • Create a templates directory in sim.
  • Create a sse.html file in sim/templates with the following content:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SSE</title>
</head>
<body>
<h1>Server Sent Events</h1>
<div id="sse-data"></div>
<button onclick="startSSE()">Start</button>
<button onclick="stopSSE()" disabled>Stop</button>

<script>
    let eventSource;
    const sseData = document.getElementById('sse-data');

    function startSSE() {
        eventSource = new EventSource('/stream/');
        eventSource.onmessage = event => sseData.innerHTML += event.data + '<br>';
        document.querySelector('button[onclick="startSSE()"]').disabled = true;
        document.querySelector('button[onclick="stopSSE()"]').disabled = false;
    }

    function stopSSE() {
        if (eventSource) {
eventSource.close();
        }
        document.querySelector('button[onclick="startSSE()"]').disabled = false;
        document.querySelector('button[onclick="stopSSE()"]').disabled = true;
    }
</script>
</body>
</html>

Run the app

  • Run the Daphne server:
python manage.py runserver

You should see something like the following output (notice the Daphne server is running):

Django version 4.2.7, using settings 'core.settings'
Starting ASGI/Daphne version 4.0.0 development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
  • Visit http://127.0.0.1:8000/sse/ in your browser. You should see the numbers 0 to 9 appear at one-second intervals. You should be able to start and stop the server sent events by clicking the buttons.


Complete ✅

That's it - You've added server sent events to your Django app 🎉. This is a minimal example to start using server-sent events with Django and Daphne.

You can now build on this to add real-time updates to your frontend.

Good uses include when your backend receives new data or when a user takes an action.

If you want to build an AI chat app using this technique, check out my guide Stream AI chats to the browser using Django in 5 minutes (OpenAI and Anthropic)💧.

P.S Build your Django frontend even faster?

Probably like you, I want to make my Django product ideas become reality as soon as possible.

That's why I built Photon Designer - a new way of building Django frontend as fast as possible, and entirely visually.

Photon Designer outputs neat, clean Django templates.

Let's get visual.

Do you want to create beautiful frontends effortlessly?
Click below to book your spot on our early access mailing list (as well as early adopter prices).
Copied link to clipboard 📋

Made with care by Tom Dekan

© 2024 Photon Designer