A Single File Asynchronous Django Application

Didn't Daphne turn into a laurel tree?

Django 3.0 alpha 1 came out this week. It introduces ASGI support thanks to lots of hard work by Andrew Godwin.

Thanks to a question from Emiliano Dalla Verde Marcozzi on the shiny new Django forums, I decided to play with it a bit. I adapted my “single file Django app” to ASGI.

Here’s how to try it yourself.

First, create a new virtual environment (I’m using Python 3.7.4) and install requirements:

$ python -m venv venv
$ source venv/bin/activate
$ pip install django==3.0a1 daphne==2.3.0

Then create a new file app.py:

import html
import os
import sys

from django.conf import settings
from django.core.asgi import get_asgi_application
from django.http import HttpResponse
from django.urls import path
from django.utils.crypto import get_random_string

    DEBUG=(os.environ.get("DEBUG", "") == "1"),
    # Disable host header validation
    # Make this module the urlconf
    # We aren't using any security features but Django requires this setting

def index(request):
    name = request.GET.get("name", "World")
    return HttpResponse(f"Hello, {html.escape(name)}!")

urlpatterns = [path("", index)]

application = get_asgi_application()

if __name__ == "__main__":
    from django.core.management import execute_from_command_line


Then run it under Daphne:

$ daphne app:application

Visit http://localhost:8000/?name=Django%20user in your browser to see “Hello, Django user!”

Async support in Django 3.0 is the first step, and limited to the outer handler layer. Middleware, views, the ORM, and everything you’re used to in Django remains synchronous. The ASGI handler achieves this by running response generation in a thread pool.

If you want to use Websockets, you’ll need a second framework for now, like Channels or Starlette.

ASGI is a simple interface with a “turtles all the way down” approach. This lets us glue our Django app to another with a “middleware” application:

django_application = get_asgi_application()
websocket_application = ...  # TODO: make it

async def application(scope, receive, send):
    if scope["type"] == "http":
        await django_application(scope, receive, send)
    elif scope["type"] == "websocket":
        await websocket_application(scope, receive, send)
        raise NotImplementedError(f"Unknown scope type {scope['type']}")

ASGI support will increase with coming Django versions. DEP 9 outlines Andrew’s plan for increasing ASGI support going forwards.


Hope this helps you get started experimenting with Django on ASGI,


Make your development more pleasant with Boost Your Django DX.

Subscribe via RSS, Twitter, Mastodon, or email:

One summary email a week, no spam, I pinky promise.

Related posts: