Now that Django 3.0 comes with ASGI support, adding Websockets to Django applications does not require any additional dependencies. In this article, you will learn how to handle Websockets with Django by extending the default ASGI application. We will cover how to handle Websocket connections, send and receive data, and implement business logic in a sample ASGI application.
introduction (a subject)
First, you need to install Python> = 3.6 on your computer. Django 3.0 is only compatible with Python 3.6 and higher because it uses the async and await keywords. After completing the Python version setup, create a project directory and CD into it. Then, install Django inside virtualenv and create a new Django application in your project directory:
$ mkdir django_websockets && cd django_websockets $ python -m venv venv $ source venv/bin/activate $ pip install django $ django-admin startproject websocket_app .
Take a look at the websocket_app directory of your Django application. You should see a file named. Its contents are shown below:
import os from import get_asgi_application ('DJANGO_SETTINGS_MODULE', 'websocket_app.settings') application = get_asgi_application()
This file provides the default Django ASGI settings and exposes an ASGI application called application, which can be run using an ASGI server such as uvicorn or daphne. Before going any further, let's look at the structure of an ASGI application.
ASGI Application Structure
ASGI or "Asynchronous Server Gateway Interface" is a specification for building asynchronous web services using Python. It is the spiritual successor to WSGI, which has been used for a long time by frameworks such as Django and Flask. ASGI enables you to use Python's native asynchronous/waiting capabilities to build web services that support long term connections, such as Websockets and Server Sent Events.
An ASGI application is an asynchronous function with 3 parameters: scope (the context of the current request), receive (an asynchronous function that lets you listen for incoming events) and send (an asynchronous function that sends events to the client).
Inside an ASGI application, you can route requests based on the values in the scope dictionary. For example, you can check whether the request is an HTTP request or a Websocket request by checking the value of scope ['type']. To listen for data from the client, you can wait for the receive function. When you are ready to send data to the client, you can wait for the send function and then pass any data to be sent to the client. Let's see how this works in the sample application.
Create an ASGI application
In our documentation, we will use our own ASGI application to wrap Django's default ASGI application functionality in order to handle websocket connections ourselves. To do this, we need to define an asynchronous function called application that takes 3 ASGI parameters: scope, receive, and send. rename the result of the get_asgi_application call to django_application since we need it to handle HTTP requests. Inside our application function, we will check the value of scope ['type'] to determine the request type. If the request type is " http", the request is a normal HTTP request and we should let Django handle it. If the request type is " websocket" then we will handle the logic ourselves. The generated file should look like the following:
import os from import get_asgi_application ('DJANGO_SETTINGS_MODULE', 'websocket_app.settings') django_application = get_asgi_application() async def application(scope, receive, send): if scope['type'] == 'http': # Let Django handle HTTP requests await django_application(scope, receive, send) elif scope['type'] == 'websocket': # We'll handle Websocket connections here pass else: raise NotImplementedError(f"Unknown scope type {scope['type']}")
Now we need to create a function to handle the websocket connection. Create a file named in the same folder as the file and define an ASGI application function named websocket_application that accepts 3 ASGI parameters. Next, we'll import websocket_application in our file and call it from inside our application function to handle the websocket request, passing in the scope, receiving and sending parameters. It should look something like this:
# import os from import get_asgi_application from websocket_app.websocket import websocket_application ('DJANGO_SETTINGS_MODULE', 'websocket_app.settings') django_application = get_asgi_application() 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) else: raise NotImplementedError(f"Unknown scope type {scope['type']}") # async def websocket_application(scope, receive, send): pass
Next, let's implement some logic for our websocket application. We will listen to all websocket connections and when the client sends the string "ping", we will respond with the string "pong!
Inside the websocket_application function, we will define an indeterminate loop that will process the websocket request until the connection is closed. Inside that loop, we will wait for any new events that the server receives from the client. We will then act on the content of the event and send the response to the client.
First, let's handle the connection. When a new websocket client connects to the server, we will receive a " "event. To allow this connection, we will send a " "event in response. This will complete the Websocket handshake and establish a persistent connection with the client.
We also need to handle the disconnect event when the client terminates its connection to the server. To do this, we will listen for the " "event. When the client disconnects, we will get rid of the uncertainty loop.
Finally, we need to handle requests from the client. To do this, we will listen for the " "event. When we receive the " " event from the client, we will check if the value of event ['text'] is " ping". If it is, we will send an ' "event with a text value of 'pong!'.
After setting up the websocket logic, our file should look like the following:
# async def websocket_application(scope, receive, send): while True: event = await receive() if event['type'] == '': await send({ 'type': '' }) if event['type'] == '': break if event['type'] == '': if event['text'] == 'ping': await send({ 'type': '', 'text': 'pong!' })
beta (software)
Now that our ASGI application is set up to handle websocket connections and we have implemented the websocket server logic, let's test it. Currently, the Django development server doesn't use files, so you won't be able to test connections using . / runserver to test connections. Instead, you will need to run the application using an ASGI server such as uvicorn. Let's install it:
$ pip install uvicorn
After installing uvicorn, we can run the ASGI application using the following command:
$ uvicorn websocket_app.asgi:application INFO: Started server process [25557] INFO: Waiting for application startup. INFO: ASGI 'lifespan' protocol appears unsupported. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
To test a Websocket connection, open your browser's developer tools in the New tab. In the console, create a new Websocket instance named ws that points to ws:// localhost:8000 /. Then attach the onmessage handler to the ws that will log to the console. Finally, call ('ping') to send the message to the server. You should see the value " pong!". Log into the console.
> ws = new WebSocket('ws://localhost:8000/') WebSocket {url: "ws://localhost:8000/", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …} > = event => () event => () > ("ping") undefined pong!
Congrats! Now you know how to add websocket support to your Django application using ASGI. Go make awesome stuff with it.
This is the whole content of this article, I hope it will help you to learn more.