Django Channels – Introduction and Basic Setup

13 Apr, 2021
Django is a powerful Python framework for web development. It is fast, secure, and reliable. Channels allow Django projects to handle HTTP along with asynchronous protocols like WebSockets, MQTT, chatbots, and more. 
Channels preserve the synchronous behavior of Django and add a layer of asynchronous protocols allowing users to write the views that are entirely synchronous, asynchronous, or a mixture of both. Channels basically allow the application to support “long-running connections”. It replaces Django’s default WSGI with its ASGI.
ASGI (Asynchronous Server Gateway Interface) provides an interface between async Python web servers and applications while it supports all the features provided by WSGI.
A consumer is a basic unit of Channels. It is an event-driven class that supports both async and sync applications. Consumers can run longer and hence they support web sockets that need persistent connection.
In this post, we will set up a basic example of channels. We will build a calculator app that will allow the user to send multiple expressions to the server and receive the result through a single persistent connection.
It is always a good idea to create a virtual environment for the python apps in order to avoid version conflicts. Run the following commands in the terminal to get started
easy-install pip
python3 -m pip install virtualenv
virtualenv venv
source venv/bin/activate
Now install Django and Channels:
pip install django
pip install channels
# On windows, try an unofficial wheel of 'Twisted' in case of dependency errors
Now start a Django project and create an app named ‘liveCalculator’
django-admin startproject sampleProject
cd sampleProject
python3 manage.py startapp liveCalculator
In sampleProject/settings.py, register channels and liveCalculator.
settings.py:
INSTALLED_APPS = [
   'channels',
   'liveCalculator',
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
]
In sampleProject/asgi.py, add the http protocol.
asgi.py:
Python3
import os  import djangofrom channels.http import AsgiHandlerfrom channels.routing import ProtocolTypeRouter  os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sampleProject.settings')django.setup()  application = ProtocolTypeRouter({  "http": AsgiHandler(),  # Just HTTP for now. (We can add other protocols later.)})
Now we need to register this asgi into our application. Add this line in sampleProject/settings.py :
ASGI_APPLICATION = "sampleProject.asgi.application"
Create a new folder liveCalculator/templates/liveCalculator and create a new file index.html inside it. It will be the starting page of our app. Add the following code in index.html:
index.html:
HTML
<!DOCTYPE html><html lang="en">  <head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Live Calculator</title></head>  <body>    <textarea name="ta" id="results" cols="30" rows="10">      </textarea><br>    Enter the expression: <input type="text" id="exp">    <input type="button" id="submit" value="Get Results">    <script>        const socket = new WebSocket('ws://localhost:8000/ws/livec/');        socket.onmessage = (e) => {            result = JSON.parse(e.data).result;            document.getElementById("results").value += "Server: " + result + "\n";        }          socket.onclose = (e) => {            console.log("Socket closed!");        }          document.querySelector('#exp').onkeyup = function (e) {            if (e.keyCode === 13) {  // enter, return                document.querySelector('#submit ').click();            }        };          document.querySelector("#submit").onclick = (e) => {            inputfield = document.querySelector("#exp")            exp = inputfield.value            socket.send(JSON.stringify(                {                    expression: exp                }            ))            document.querySelector("#results").value += "You: " + exp + "\n";            inputfield.value = "";        }      </script></body>  </html>
The above code will render a text area and an input box where the user can enter the expression. It will create a socket connection that we will make later and append the received result in the text area. When the user inputs the expression, it will send the expression through a socket connection.
Now create a view to render this page in liveCalculator/views.py :
liveCalculator/views.py:
Python3
from django.shortcuts import render  # Create your views here.  def index(request):    return render(request, 'liveCalculator/index.html', {})
Next, we need to create a route for this view. Add a new file urls.py in liveCalculator directory and add the following code:
liveCalculator/urls.py:
Python3
from django.conf.urls import urlfrom . import views  urlpatterns = [    url(r'^$', views.index, name="index"),]
Register this route in sampleProject/urls.py :
sampleProject/urls.py:
Python3
from django.contrib import adminfrom django.urls import pathfrom django.conf.urls import include, urlurlpatterns = [    path('admin/', admin.site.urls),    url(r'^', include('liveCalculator.urls'))]
Now we need to create the consumer for our web socket connection. We will use the generic WebsocketConsumer class to implement its event-driven methods. Create a new file consumers.py in liveCalculator folder and add the following code:
consumers.py:
Python3
import jsonfrom channels.generic.websocket import WebsocketConsumer  class Calculator(WebsocketConsumer):    def connect(self):        self.accept()      def disconnect(self, close_code):        self.close()         def receive(self, text_data):        text_data_json = json.loads(text_data)        expression = text_data_json['expression']        try:            result = eval(expression)        except Exception as e:            result = "Invalid Expression"        self.send(text_data=json.dumps({            'result': result        }))
The WebsocketConsumer class supports these user-defined methods:
connect(): We can write the business logic of what should happen when the client sends a connection request.
disconnect(): We can write the business logic of what should happen when the client sends a disconnection request.
receive(): We can write the business logic of what should happen when the client sends a message.
It also supports these built-in methods:
accept(): It will accept the incoming connection.
close(): It will close the current connection.
send(): It will send the specified message to the client.
We have simply used the above methods in our Calculator class to accept the connection, evaluate the expression when a message a received, and send it to the client.
Next, we also need to define the routing method for this consumer. Create a new file routing.py in the same folder and add the following code to it:
routing.py:
Python3
from django.urls import re_path  from . import consumers  websocket_urlpatterns = [    re_path(r'ws/livec/$', consumers.Calculator.as_asgi()),]
Note that we have used as_asgi() method on our Calculator class to use it for our application. This will enable the socket on ws://<IP:Port>/ws/livec. Now register routing.py into asgi.py by declaring the WebSocket protocol. 
asgi.py:
Python3
import os  from channels.auth import AuthMiddlewareStackfrom channels.routing import ProtocolTypeRouter, URLRouterfrom django.core.asgi import get_asgi_applicationimport liveCalculator.routing  os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sampleProject.settings")  application = ProtocolTypeRouter({  "http": get_asgi_application(),  "websocket": AuthMiddlewareStack(        URLRouter(            liveCalculator.routing.websocket_urlpatterns        )    ),})
We are almost done with our first Channels application. Save all the files and run the following commands in the terminal:
python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py runserver
Now open http://localhost:8000 on your browser, and you should see the output like this:
See the log of the server. Note that we have created the connection only once, and we can send the message multiple times without creating a new connection. 
Socket-programming
Python
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.