Django is a great Web framework for server side , Angular is a great JS framework for client side. While Integrating both frameworks, we get many benefits.

This is the 3rd post about integrating both frameworks

For getting started tutorial for using both Angular and Django see this post

For integrating data packages – numpy, spicy, pandas and more see this post

If we want to develop Real time web applications or we want to get notification from the server to the client without the need to poll it periodically, we can use Web Sockets.

The infrastructure for web sockets in django is – channels – For simple example of using channels in django see this post

The server side – Django

To use channels in django we need to add it to the installed apps and config a backend (in this case redis server) :

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'channels', 'example', ] 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 10 11 12 13 14 15 16 17 18 19 20 INSTALLED_APPS = [ 'django.contrib.admin' , 'django.contrib.auth' , 'django.contrib.contenttypes' , 'django.contrib.sessions' , 'django.contrib.messages' , 'django.contrib.staticfiles' , 'channels' , 'example' , ] CHANNEL_LAYERS = { 'default' : { 'BACKEND' : 'asgi_redis.RedisChannelLayer' , 'CONFIG' : { 'hosts' : [ ( 'localhost' , 6379 ) ] , } , 'ROUTING' : 'chantest.routing.channel_routing' , } }

Then we need to create a channel routing table for the channel events:

channel_routing = [ route('websocket.connect', ws_connect), route('websocket.disconnect', ws_disconnect), route("websocket.receive", ws_message), ] 1 2 3 4 5 channel_routing = [ route ( 'websocket.connect' , ws_connect ) , route ( 'websocket.disconnect' , ws_disconnect ) , route ( "websocket.receive" , ws_message ) , ]

This declares that on web socket new connection ws_connect function with be called , on disconnect ws_disconnect and every time we get a message from the client ws_message will be called

To implement the event handlers we add a consumers.py file:

import json from channels import Group from channels.auth import channel_session_user, channel_session_user_from_http import threading import random def sendmsg(num): Group('stocks').send({'text':num}) t = 0 def periodic(): global t; n = random.randint(100,200); sendmsg(str(n)) t = threading.Timer(1, periodic) t.start() def ws_message(message): global t print(message.content['text']) if ( message.content['text'] == "start"): periodic() else: t.cancel() # message.reply_channel.send({'text':'200'}) 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 33 34 35 import json from channels import Group from channels . auth import channel_session_user , channel_session_user_from_http import threading import random def sendmsg ( num ) : Group ( 'stocks' ) . send ( { 'text' : num } ) t = 0 def periodic ( ) : global t ; n = random . randint ( 100 , 200 ) ; sendmsg ( str ( n ) ) t = threading . Timer ( 1 , periodic ) t . start ( ) def ws_message ( message ) : global t print ( message . content [ 'text' ] ) if ( message . content [ 'text' ] == "start" ) : periodic ( ) else : t . cancel ( ) # message.reply_channel.send({'text':'200'}) 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 )

In this example we are waiting for message ‘start’ , then we start a periodic timer to generate a random number and send it to the client using the socket

To integrate Angular we need to add the following setting (to the setting.py file):

PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles') STATIC_URL = '/static/' # Extra places for collectstatic to find static files. STATICFILES_DIRS = ( os.path.join(PROJECT_ROOT, 'static'), ) 1 2 3 4 5 6 7 8 PROJECT_ROOT = os.path . dirname ( os.path . abspath ( __file__ ) ) STATIC_ROOT = os.path . join ( PROJECT_ROOT , 'staticfiles' ) STATIC_URL = '/static/' # Extra places for collectstatic to find static files. STATICFILES_DIRS = ( os.path . join ( PROJECT_ROOT , 'static' ) , )

Also create a directory ‘static’ to put the generated javascript files



The Client side – Angular

To use web socket we build a simple Angular application with 2 buttons – to send start and stop commands:

On start click the client will send ‘start’ on the socket and the server will start send random numbers every 1 second:

The template:

<div style="text-align:center"> <h1> WebSockets Example Current value:{{num}} </h1> <button (click)="start()">Start</button> <button (click)="stop()">Stop</button> </div> 1 2 3 4 5 6 7 < div style = "text-align:center" > < h1 > WebSockets Example Current value : { { num } } < / h1 > < button ( click ) = "start()" > Start < / button > < button ( click ) = "stop()" > Stop < / button > < / div >

To create Web socket:

setsock() { this.socket = new WebSocket('ws://' + window.location.host + '/stocks/'); this.socket.onopen = () => { console.log('WebSockets connection created.'); }; this.socket.onmessage = (event) => { console.log("data from socket:" + event.data); this.num = event.data; }; if (this.socket.readyState == WebSocket.OPEN) { this.socket.onopen(null); } } start() { this.socket.send('start'); } stop() { this.socket.send('stop'); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 setsock ( ) { this . socket = new WebSocket ( 'ws://' + window . location . host + '/stocks/' ) ; this . socket . onopen = ( ) = > { console . log ( 'WebSockets connection created.' ) ; } ; this . socket . onmessage = ( event ) = > { console . log ( "data from socket:" + event . data ) ; this . num = event . data ; } ; if ( this . socket . readyState == WebSocket . OPEN ) { this . socket . onopen ( null ) ; } } start ( ) { this . socket . send ( 'start' ) ; } stop ( ) { this . socket . send ( 'stop' ) ; }

We can also use RxJS to create observable and observer:

public messages: Subject<string>; private connect(url): Subject<MessageEvent> { let ws = new WebSocket(url); let observable = Observable.create( (obs: Observer<MessageEvent>) => { ws.onmessage = obs.next.bind(obs); ws.onerror = obs.error.bind(obs); ws.onclose = obs.complete.bind(obs); return ws.close.bind(ws); }) let observer = { next: (data: string) => { if (ws.readyState === WebSocket.OPEN) { ws.send(data); if(data=="stop") ws.close(1000,"bye") } } } return Subject.create(observer, observable); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public messages: Subject < string > ; private connect ( url ) : Subject < MessageEvent > { let ws = new WebSocket ( url ) ; let observable = Observable . create ( ( obs : Observer < MessageEvent > ) = > { ws . onmessage = obs . next . bind ( obs ) ; ws . onerror = obs . error . bind ( obs ) ; ws . onclose = obs . complete . bind ( obs ) ; return ws . close . bind ( ws ) ; } ) let observer = { next : ( data : string ) = > { if ( ws . readyState === WebSocket . OPEN ) { ws . send ( data ) ; if ( data == "stop" ) ws . close ( 1000 , "bye" ) } } } return Subject . create ( observer , observable ) ; }

We can implement it as a service (here it is in the component)

Now we can subscribe to receive messages and use the next method to send:

start() { this.messages.next("start"); } stop() { this.messages.next("stop"); } ngOnInit(){ this.messages = <Subject<string>>this.connect('ws://' + window.location.host + '/stocks/') .map((response: MessageEvent): string => { return response.data }) this.messages.subscribe(msg => { console.log("from server:" + msg); this.num = msg; } ) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 start ( ) { this . messages . next ( "start" ) ; } stop ( ) { this . messages . next ( "stop" ) ; } ngOnInit ( ) { this . messages = < Subject < string >> this . connect ( 'ws://' + window . location . host + '/stocks/' ) . map ( ( response : MessageEvent ) : string = > { return response . data } ) this . messages . subscribe ( msg = > { console . log ( "from server:" + msg ) ; this . num = msg ; } ) }

To deploy the angular code use:

# ng build 1 # ng build

and copy the js files to the static directory in django project

Change the index.html file to integrate django:

{% load static %} <!doctype html> <html> <head> <meta charset="utf-8"> <title>Home1</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <!-- index.html --> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <app-root>Loading...</app-root> <script type="text/javascript" src="{% static 'inline.bundle.js' %}"></script> <script type="text/javascript" src="{% static 'polyfills.bundle.js' %}"></script> <script type="text/javascript" src="{% static 'styles.bundle.js' %}"></script> <script type="text/javascript" src="{% static 'vendor.bundle.js' %}"></script> <script type="text/javascript" src="{% static 'main.bundle.js' %}"></script></body> </html> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 { % load static % } < ! doctype html > < html > < head > < meta charset = "utf-8" > < title > Home1 < / title > < base href = "/" > < meta name = "viewport" content = "width=device-width, initial-scale=1" > < link rel = "icon" type = "image/x-icon" href = "favicon.ico" > < ! -- index . html -- > < link href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel = "stylesheet" > < / head > < body > < app - root > Loading . . . < / app - root > <script type = "text/javascript" src = "{% static 'inline.bundle.js' %}" > </script> <script type = "text/javascript" src = "{% static 'polyfills.bundle.js' %}" > </script> <script type = "text/javascript" src = "{% static 'styles.bundle.js' %}" > </script> <script type = "text/javascript" src = "{% static 'vendor.bundle.js' %}" > </script> <script type = "text/javascript" src = "{% static 'main.bundle.js' %}" > </script> < / body > < / html >

Now run redis server and python server to see the results

You can find the full code here