The simplest way to add server sent events to Django 🏺

Published: November 20, 2023

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 + '')
        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)πŸ’§.

Subscribe to my free newsletter

Get updates on AI, software, and business.