Now that Django 3.0 ships with support out of the box, adding Websockets to your Django app requires no extra dependencies. In this post, you'll learn how to handle Websockets with Django by extending the default ASGI application. We'll go over how to handle Websocket connections, send and receive data, and implement the business logic in a sample ASGI application. ASGI Getting started To start, you'll need Python >= 3.6 installed on your machine. Django 3.0 is only compatible with Python 3.6 and up because it makes use of the and keywords. Once you've got your Python version setup, create a project directory and into it. Then, install Django inside of a and create a new Django app in your project directory: async await cd virtualenv $ mkdir django_websockets && django_websockets $ python -m venv venv $ venv/bin/activate $ pip install django $ django-admin startproject websocket_app . cd source Take a look in the directory of your Django app. You should see a file called . Its contents will look something like this: websocket_app asgi.py os django.core.asgi get_asgi_application os.environ.setdefault( , ) application = get_asgi_application() import from import 'DJANGO_SETTINGS_MODULE' 'websocket_app.settings' This file provides the default Django ASGI setup, and exposes an ASGI called application which can be run using an ASGI server such as or . Before we go much further, let's take a look at how ASGI applications are structured. application uvicorn daphne ASGI app structure , or the Asynchronous Server Gateway Interface, is a specification for building asynchronous web services with Python. It's the spiritual successor to WSGI, which has been used by frameworks like Django and Flask for a long time. ASGI lets you use Python's native / functionality to build web services that support long-lived connections, such as Websockets and Server Sent Events. ASGI async await An ASGI application is a single function which takes in 3 parameters: (the context of the current request), (an function that lets you listen for incoming events), and (an function that lets you send events to the client). async scope receive async send async Inside of an ASGI application, you can route requests based on values in the dictionary. For example, you can check whether the request is an HTTP request or a Websocket request by checking the value of . To listen for data from the client, you can the function. When you're ready to send data to the client, you can the function, and pass in any data you want to send to the client. Let's take a look at how this works in a sample application. scope scope['type'] await receive await send Creating an ASGI app In our file, we're going to wrap Django's default ASGI application function with our own ASGI application in order to handle Websocket connections ourselves. To do this, we'll need to define an function called , that takes in the 3 ASGI parameters: , , and . Rename the result of the call to , because we'll need it process HTTP requests. Inside of our function we'll check the value of to determine the request type. If the request type is , then the request is a normal HTTP request and we should let Django handle it. If the request type is , then we'll want to handle the logic ourselves. The resulting file should look something like this: asgi.py async application scope receive send get_asgi_application django_application application scope['type'] 'http' 'websocket' asgi.py os django.core.asgi get_asgi_application os.environ.setdefault( , ) django_application = get_asgi_application() scope[ ] == : django_application(scope, receive, send) scope[ ] == : : NotImplementedError( ) import from import 'DJANGO_SETTINGS_MODULE' 'websocket_app.settings' async : def application (scope, receive, send) if 'type' 'http' # Let Django handle HTTP requests await elif 'type' 'websocket' # We'll handle Websocket connections here pass else raise f"Unknown scope type " {scope[ ]} 'type' Now we need to create a function to handle Websocket connections. Create a file called in the same folder as your file, and define an ASGI application function called that takes in the 3 ASGI parameters. Next, we'll import in our file, and call it inside of our function to handle Websocket requests, passing in the , , and parameters. It should look something like this: websocket.py asgi.py websocket_application websocket_application asgi.py application scope receive send os django.core.asgi get_asgi_application websocket_app.websocket websocket_application os.environ.setdefault( , ) django_application = get_asgi_application() scope[ ] == : django_application(scope, receive, send) scope[ ] == : websocket_application(scope, receive, send) : NotImplementedError( ) # asgi.py import from import from import 'DJANGO_SETTINGS_MODULE' 'websocket_app.settings' async : def application (scope, receive, send) if 'type' 'http' await elif 'type' 'websocket' await else raise f"Unknown scope type " {scope[ ]} 'type' # websocket.py async : def websocket_application (scope, receive, send) pass Next, let's implement some logic for our Websocket application. We're going to listen for all Websocket connections, and when the client sends the string , we'll respond with the string . "ping" "pong!" Inside of the function, we're going to define an indefinite loop that will handle Websocket requests until the connection is closed. Inside that loop, we'll wait for any new events that the server receives from the client. Then we'll act on the contents of the event, and send the response to the client. websocket_application To start, let's handle connections. When a new Websocket client connects to the server, we'll receive a event. In order to allow this connection, we'll send a event in response. This will complete the Websocket handshake and establish a persistent connection with the client. 'websocket.connect' 'websocket.accept' We'll also need to handle disconnection events when a client terminates their connection to the server. To do that, we'll listen for a event. When a client disconnects, we'll break out of our indefinite loop. 'websocket.disconnect' Finally, we need to handle requests from the client. To do that, we'll listen for a event. When we receive a event from the client, we'll check and see if the value of is . If it is, we'll send a event, with a text value of . 'websocket.receive' 'websocket.receive' event['text'] 'ping' 'websocket.send' 'pong!' After setting up the Websocket logic, our file should look something like this: websocket.py : event = receive() event[ ] == : send({ : }) event[ ] == : event[ ] == : event[ ] == : send({ : , : }) # websocket.py async : def websocket_application (scope, receive, send) while True await if 'type' 'websocket.connect' await 'type' 'websocket.accept' if 'type' 'websocket.disconnect' break if 'type' 'websocket.receive' if 'text' 'ping' await 'type' 'websocket.send' 'text' 'pong!' Testing it out Now our ASGI application is set up to handle Websocket connections and we've implemented our Websocket server logic, let's test it out. Right now, the Django development server doesn't use the file, so you won't be able to test your connections using . Instead, you'll need to run the app with an ASGI server such as . Let's install it: asgi.py ./manage.py runserver uvicorn $ pip install uvicorn Once is installed, we can run our ASGI application using the following command: uvicorn $ uvicorn websocket_app.asgi:application INFO: Started server process [ ] INFO: Waiting application startup. INFO: ASGI protocol appears unsupported. INFO: Application startup complete. INFO: Uvicorn running on http:// : (Press CTRL+C to quit) 25557 for 'lifespan' 127.0 .0 .1 8000 To test the Websocket connection, open up your browser's development tools in a new tab. In the console, create a new instance called pointed to . Then attach an handler to that logs to the console. Finally, call to send the message to the server. You should see the value logged to the console. Websocket ws ws://localhost:8000/ onmessage ws event.data ws.send('ping') "pong!" > ws = WebSocket( ) WebSocket { : , : , : , : , : , …} > ws.onmessage = .log(event.data) event => .log(event.data) > ws.send( ) pong! new 'ws://localhost:8000/' url "ws://localhost:8000/" readyState 0 bufferedAmount 0 onopen null onerror null => event console console "ping" undefined Congrats! Now you know how to add Websocket support to your Django application using ASGI. Go build something awesome with it 😎 👋 Hi, I'm Jayden. I love building apps and teaching others how to build apps. For more posts about building apps with Django, React, and GraphQL, follow me on Twitter or subscribe to my newsletter at jaydenwindle.com .