Angular and Django – WebSockets Communication

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',
    }
}

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),
]

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)

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'),
)

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>

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');
}

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);
  }

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;
      }

    )
  }

To deploy the angular code use:

# 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>

Now run redis server and python server to see the results

You can find the full code here

Subscribe To Our Mailing List
Loading

3 thoughts on “Angular and Django – WebSockets Communication

  1. I agree, Django-backend, Angular-frontend is a fantastic end-to-end framework-set; there is quite a bit of information around about coupling these two together with Django REST Framework (DRF) API.
    This is the first (‘restless’ API) article I’ve seen using ‘sockets’ for Django/Angular which IMHO really makes the most of ‘reactive’ programming patterns.
    Awesome, I’m looking forward to trying it out. I’d love to see something like this on a training site like Udemy, pluralsite, cfe, … or even youtube, with Angular/CLI and perhaps ngPrime as a replacement for bootstrap.
    Thanks so much for the post, great set of three posts on this subject.

  2. which JS files DOi need to copy to static folder?

  3. tHANK YOU FOR THE EXAMPLE. IT HELPS A LOT. BUT CAN YOU PLEASE ELABORATE HOW TO CONFIGURE CHANNELS IN ANGULAR? i AM NOT TALKING ABOUT THE USAGE. THANK YOU

Comments are closed.