Django is a great python web framework for server side. If we want to communicate with the client it can be done using the request-response model and also using a web socket especially when we want to send push notifications to the client.

This is a very simple example of how to create and communicate using a channel (web socket) it can be used as a starter for any web application with channels need

First step is to create and activate virtual environment

# virtualenv -p /usr/local/bin/python3 env # source env/bin/activate 1 2 # virtualenv -p /usr/local/bin/python3 env # source env/bin/activate

Install django and create a new app

# pip install django # django-admin startproject chantest # cd chantest/ # python manage.py startapp example 1 2 3 4 # pip install django # django-admin startproject chantest # cd chantest/ # python manage.py startapp example

install channels for web sockets support and asgi_redis for using redis-server as a backend

# pip install channels asgi_redis 1 # pip install channels asgi_redis

Add the channels and example to the installed apps (in settings.py)

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'channels', 'example', ] 1 2 3 4 5 6 7 8 9 10 INSTALLED_APPS = [ 'django.contrib.admin' , 'django.contrib.auth' , 'django.contrib.contenttypes' , 'django.contrib.sessions' , 'django.contrib.messages' , 'django.contrib.staticfiles' , 'channels' , 'example' , ]

Add the channel configuration at the end of the settings.py file:

CHANNEL_LAYERS = { 'default': { 'BACKEND': 'asgi_redis.RedisChannelLayer', 'CONFIG': { 'hosts': [('localhost', 6379)], }, 'ROUTING': 'chantest.routing.channel_routing', } } 1 2 3 4 5 6 7 8 9 CHANNEL_LAYERS = { 'default' : { 'BACKEND' : 'asgi_redis.RedisChannelLayer' , 'CONFIG' : { 'hosts' : [ ( 'localhost' , 6379 ) ] , } , 'ROUTING' : 'chantest.routing.channel_routing' , } }

It defines the backend as redis server and set the port

install redis server

For Mac # brew install redis For Linux (ubuntu) # sudo apt-get install redis-server 1 2 3 4 5 For Mac # brew install redis For Linux ( ubuntu ) # sudo apt-get install redis-server

start the redis server

# redis-server 1 # redis-server

run migrate and the server

# python manage.py migrate # python manage.py runserver 1 2 # python manage.py migrate # python manage.py runserver

Edit the file urls.py:

from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include('example.urls', namespace='example')), ] 1 2 3 4 5 6 7 from django . conf . urls import url , include from django . contrib import admin urlpatterns = [ url ( r '^admin/' , admin . site . urls ) , url ( r '^' , include ( 'example.urls' , namespace = 'example' ) ) , ]

Add urls.py file to the folder example

from django.conf.urls import url from example import views urlpatterns = [ url(r'^$', views.HomePageView.as_view()), ] 1 2 3 4 5 6 from django . conf . urls import url from example import views urlpatterns = [ url ( r '^$' , views . HomePageView . as_view ( ) ) , ]

Add a simple view to views.py file:

# Create your views here. from django.shortcuts import render from django.views.generic import TemplateView # Create your views here. class HomePageView(TemplateView): def get(self, request, **kwargs): return render(request, 'index.html', context=None) 1 2 3 4 5 6 7 8 9 # Create your views here. from django . shortcuts import render from django . views . generic import TemplateView # Create your views here. class HomePageView ( TemplateView ) : def get ( self , request , * * kwargs ) : return render ( request , 'index.html' , context = None )

Add a template folder (below example) and add index.html file:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script> var socket = new WebSocket('ws://' + window.location.host + '/stocks/'); socket.onopen = function open() { console.log('WebSockets connection created.'); }; socket.onmessage = function message(event) { console.log("data from socket:" + event.data); lbl.innerText = event.data; }; if (socket.readyState == WebSocket.OPEN) { socket.onopen(); } function start() { socket.send('start'); } function stop() { socket.send('stop'); } </script> </head> <body> <h2>hello</h2> <button onclick="start()">Start</button> <button onclick="stop()">Stop</button> <label id="lbl">Data</label> </body> </html> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 < ! DOCTYPE html > < html lang = "en" > < head > < meta charset = "UTF-8" > < title > Title < / title > <script> var socket = new WebSocket ( 'ws://' + window . location . host + '/stocks/' ) ; socket . onopen = function open ( ) { console . log ( 'WebSockets connection created.' ) ; } ; socket . onmessage = function message ( event ) { console . log ( "data from socket:" + event . data ) ; lbl . innerText = event . data ; } ; if ( socket . readyState == WebSocket . OPEN ) { socket . onopen ( ) ; } function start ( ) { socket . send ( 'start' ) ; } function stop ( ) { socket . send ( 'stop' ) ; } </script> < / head > < body > < h2 > hello < / h2 > < button onclick = "start()" > Start < / button > < button onclick = "stop()" > Stop < / button > < label id = "lbl" > Data < / label > < / body > < / html >

In the above code we open a web socket on load and connect to the server. We also added 2 buttons to send ‘start’ and ‘stop’ command to the socket and label for data received

Add the file routing.py to chantest directory: (as we declared it in settings.py file)

from channels.routing import route from example.consumers import ws_connect, ws_disconnect, ws_message channel_routing = [ route('websocket.connect', ws_connect), route('websocket.disconnect', ws_disconnect), route("websocket.receive", ws_message), ] 1 2 3 4 5 6 7 8 9 from channels . routing import route from example . consumers import ws_connect , ws_disconnect , ws_message channel_routing = [ route ( 'websocket.connect' , ws_connect ) , route ( 'websocket.disconnect' , ws_disconnect ) , route ( "websocket.receive" , ws_message ) , ]

Add consumer.py file to example directory:

from channels import Group import threading import random def sendmsg(num): Group('stocks').send({'text':num}) t = 0 def periodic(): global t; n = random.randint(10,200); sendmsg(str(n)) t = threading.Timer(5, periodic) t.start() def ws_message(message): global t print(message.content['text']) if ( message.content['text'] == 'start'): periodic() else: t.cancel() def ws_connect(message): Group('stocks').add(message.reply_channel) Group('stocks').send({'text':'connected'}) def ws_disconnect(message): Group('stocks').send({'text':'disconnected'}) Group('stocks').discard(message.reply_channel) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from channels import Group import threading import random def sendmsg ( num ) : Group ( 'stocks' ) . send ( { 'text' : num } ) t = 0 def periodic ( ) : global t ; n = random . randint ( 10 , 200 ) ; sendmsg ( str ( n ) ) t = threading . Timer ( 5 , periodic ) t . start ( ) def ws_message ( message ) : global t print ( message . content [ 'text' ] ) if ( message . content [ 'text' ] == 'start' ) : periodic ( ) else : t . cancel ( ) def ws_connect ( message ) : Group ( 'stocks' ) . add ( message . reply_channel ) Group ( 'stocks' ) . send ( { 'text' : 'connected' } ) def ws_disconnect ( message ) : Group ( 'stocks' ) . send ( { 'text' : 'disconnected' } ) Group ( 'stocks' ) . discard ( message . reply_channel )

Test your work – click on start to see the generated numbers in the label and click on stop to disable it

You can download the code from github