Introduction to real-time web with Django

What can you do with 20 lines of code?

Thorgate
Thorgate
5 min readNov 5, 2015

--

With the evolution of the web, it has become increasingly necessary to add more interactivity to our web applications and real-time communications is often an important part of that.
Django doesn’t have any out-of-the-box support for real-time communications, but that does not mean that achieving it is difficult. Here we look at some easy ways of adding real-time communications to your application.

Django and real-time / PubSub

Django, by default, uses a strict request-response cycle. The client sends an HTTP request, Django receives it, processes it synchronously and returns a response. However, sometimes it is useful to keep pushing updates to clients after the initial response has been returned. We will achieve this using real-time communication.

Often one does not require bidirectional realtime communication between the server and its clients. You just want to push updates and notifications from the server to the clients as they happen.

Just pushing real-time updates to clients is often enough

This pattern is commonly called PubSub, aka publish and subscribe, and there are many external services that can accomplish this for you. It’s often a good idea to use existing pieces as building blocks for your application and not to reinvent the wheel. That way, you can focus on your own app instead of the infrastructure that supports it.

Commercial PubSub services include PubNub and Pusher, however, self-hosted open-source options are also available, including Pushpin.
They all work in a similar fashion and today we’ll be looking a bit closer at Pusher.

Using Pusher

Pusher is a service that lets you easily send messages and do pub/sub without needing to mess about with websockets yourself.
Getting started is rather simple:

  • Sign up at pusher.com
  • Add server-side code that sends messages.
  • Add client-side code that listens to messages and reacts to them.
  • You’re all done!

Let’s look at how we can publish messages from our server via Pusher:

  • First we create the Pusher instance using credentials found within Pusher’s admin interface.
  • then we use .trigger() function to send the message.
  • first argument to trigger() is the channel — this basically selects which clients receive the message. Think of it as of chat channels.
  • next is the event name — in our case showMessage. This is type of the message, specific to your application.
  • and finally we have the data. This, too, is specific to your application and message type.
# Create Pusher client
pusher = Pusher(
app_id=’121933',
key=’f1ebb516981a3315e492',
secret=’SECRET’
)

# … and send the message!
pusher.trigger(‘test_channel’, ‘showMessage’, {
‘message’: message,
})

Now that we’re all set to send messages, we want the other side to receive them. Let’s look at the Javascript code running in browser that subscribes to our channel and receives the messages.

  • First step is once again creating the Pusher instance, this time in Javascript.
  • Then we subscribe to a channel, essentially saying we’re interested in messages sent to that channel.
  • Finally, we add event handler that’s called when a message with specific type is received.
  • Here we show alert() dialog with received message.
// Create Pusher client
var pusher = new Pusher(‘f1ebb516981a3315e492’);
// Subscribe to events on our channel
var channel = pusher.subscribe(‘test_channel’);
// And react to showMessage events
channel.bind(‘showMessage’, function(data) {
alert(data.message);
});

Combined with the server code, we can now send realtime notifications to our users, without needing long-lived connections to our server.

We also want to communicate the other way — send messages from client to server. Often making a simple AJAX request is enough there. No need to complicate things without a good reason.

$.post(SUBMIT_URL, {
message: message,
});

Adding basic realtime functionality to your app takes just 20 lines of code

As shown, it’s often possible to add some real-time functionality to your app very easily. Overall, you’ll need to add around 20 lines of code, most of which can be copied from Pusher website. And that already gets the ball rolling — you’re making your UI more fluid and more user-friendly.

Going Further with WebSockets

Using an external, hosted service is a great way to get started, but sometimes you need more. When lower latency, direct control and bidirectional communication is needed, WebSockets is the next logical step to take.

WebSockets give you a direct connection between browser and server that’s persistent, low-overhead and fast. You can send both text as well as binary data, in fact we’re using it in a project that controls smart streetlights. WebSockets became a standard in 2011 and is now available in all modern browsers.

So let’s look at how we can make Django and WebSockets play together.
Again, there are several ways to do this, this is just one of them.

Python 3.3 introduced asyncio library which is the way to write applications that need to do multiple things at once, such as communicating with multiple clients and keeping those connections active for long time. There is a Python websockets package available that builds on top of asyncio, taking care of the low-level details of the WebSockets protocol.

The WebSockets server will be running on a different port than the main application, so we’ll be using a custom server process for that.
We define a handler function which will be run whenever a new client connects. The handler function communicates with a single client, sending and receiving messages.

@asyncio.coroutine
def client_handler(websocket, uri):
# Send a message
yield from websocket.send(“Hello world”)
# Wait for a reply
msg = yield from websocket.recv()

We could expand this into a simple loop that listens to messages that a client sends, and then does some processing with them.
Some code here has been omitted for brevity, but overall, it’s still easy to get started.

@asyncio.coroutine
def client_handler(websocket, uri):
# Send a message
yield from websocket.send(“Hello world”)
# Read all messages while the socket is open
while True:
msg = yield from websocket.recv()
if msg is None:
# Oops, the socket has closed
return
# Fancy message processing
print(“got message:”, msg)

For the client part, we could use pure JS. The API is quite simple and clear.
Here however I’ve chosen to use a small wrapper lib SawKit.

In the following example, we’ll connect to the server, emit a message, and then define a handler function for incoming messages of certain type.

// Connect to the server
$ws(‘ws://localhost:8080’).ready(function($ws, ws) {
// When connection is made, send a message
$ws.emit(‘showMessage’, {
msg: ‘WebSockets are fun!’,
});
// And react to incoming messages
$ws.on(‘showMessage’, function(data) {
alert(data.message);
});
});

Just Do It!

In conclusion, adding real-time to your app is easy. Two simple ways were demonstrated here.

Services like Pusher make it ridiculously easy to get started with pushing realtime updates to clients, which is often enough.
If you need more power, use WebSockets, which isn’t really difficult to set up either.

There are also other interesting technologies coming up which let you combine Django and realtime communication in different ways, such as Django Channels, SwampDragon or Pushpin (along with Django-GRIP package).

See also:
Push API — https://developer.mozilla.org/en-US/docs/Web/API/Push_API

Demo: http://djangocon.thorgate.eu
Code: https://github.com/rivol/djangocon-realtime

PS. Did you know the biggest Python event in Northern Europe, PyCon Estonia 2019, is just around the corner?
Check it out here: http://bit.ly/pyconestonia

--

--

Thorgate
Thorgate

We are THE digital product company. We think people, not products and that is how we develop world-changing ideas, with passion and for impact.