[go: up one dir, main page]

0% found this document useful (0 votes)
256 views9 pages

Introduction To Django Channels

This document discusses how Django Channels extends the Django framework to enable real-time capabilities. Django Channels adds an asynchronous layer to handle websockets and background tasks. It uses the ASGI protocol instead of WSGI to support asynchronous requests. When a request arrives via Channels, it will be routed either to a Django view for HTTP requests or to a consumer for websocket requests. Consumers are similar to views and handle incoming messages. The document provides an example of building a price monitoring app with Channels that displays cryptocurrency prices in real time.

Uploaded by

Ed Cornejo Mayta
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
256 views9 pages

Introduction To Django Channels

This document discusses how Django Channels extends the Django framework to enable real-time capabilities. Django Channels adds an asynchronous layer to handle websockets and background tasks. It uses the ASGI protocol instead of WSGI to support asynchronous requests. When a request arrives via Channels, it will be routed either to a Django view for HTTP requests or to a consumer for websocket requests. Consumers are similar to views and handle incoming messages. The document provides an example of building a price monitoring app with Channels that displays cryptocurrency prices in real time.

Uploaded by

Ed Cornejo Mayta
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

In this article, we’re going to talk about Django channels and how it can be a game changer for the

Django
framework.

Django is an already established framework in the market, but it is synchronous and nowadays with the high
demand for real time applications, It could not be left behind. Django channels comes into play to solve this
issue.

Django channels’ goal is to extend the Django framework, adding to it a new layer to handle the use of
WebSockets and background tasks.

To use as an example, we’re going to create a simple webapp called coinpricemonitor, to watch the bitcoin and
litecoin prices in real time. If you want to take a look at the full code, it’s here. To create this example I used
Django 1.11 and Channels 1.1.6.

What do I have to change to use Django channels?


All that comes with Channels is entirely optional and, as said before, It just aims to extend Django, giving it the
ability to create real time applications. It would not be good if a new release of the framework would break
everyone’s request system.

If Django Channels was in the core of Django already, as it intends to be in the future, you wouldn’t need to
install anything. You would only have to update your project to Django’s newest release.

How to install
While Channels is not in the core of Django yet, we need to install it. In order to do it, just run the
command:  pip install channels .

After that, add  channels  to your  INSTALLED_APPS  tuple.

Django channels request cycle


Using Channels, now you will have two types of requests to handle, the http requests and the websocket
requests.

When the request arrives from the client, it will pass through an Interface server, a server that understands the
ASGI (Asynchronous Server Gateway Interface) protocol. It will redirect the request to an ASGI router, the
channel layer that will check if it’s a http request, and send it to its respective view, or a websocket request,
and send it to its consumer, which is very similar to a view.

In the following sections, we will see these components that integrate the new request cycle with Channels.

ASGI server
Nowadays the Django framework uses a WSGI (Web Server Gateway Interface), which is an interface for python
applications to handle requests. But to work with asynchronous applications, we need to use another interface,
which is ASGI (Asynchronous Server Gateway Interface), that can handle websocket requests as well.
You will have to use a server that uses this approach. Good for us that Andrew Goodwin, the creator of Channels,
made as well a server called  Daphne . To handle this protocol as well.

Daphne already comes with Channels, so you won’t need to install it.

ASGI router
Now, you are handling two types of requests: the http requests that are going to be routed to views as normal,
and websocket requests that are going to be routed to consumers, which are similar to your already known
views. To handle both requests we need a router. It is a part of the channel layer, which is the backend of
Channels.

Some brokers that can be used as routers are:

asgi_redis — You will need to install Redis to use this broker.

asgi_rabbitmq — You will need to install Rabbitmq to use this broker.

asgiref

You can find all these brokers in PyPI, meaning that you can use  easy_install  or  pip  to install them.

Here’s an example how to setup the channel layer with the  asgi_redis broker:

settings.py

It’s quite simple to setup the channels layer, here’s the meaning of each key:

default — Default settings for the channel layer.

BACKEND — Broker you are going to use. In our case,  asgi_redis .

CONFIG — Configurations of the channels, like hosts and capacity of each channel. You can check out all
options here.

ROUTING — To where the incoming messages are going to be routed to.

Web workers
They are the ones that are going to process the consumers.
Basic concepts
Channel
The main data structure in Channels is a Channel, and its concept is described as:

Channel is a data structure that is a first­in first­out queue It is an ordered, first-in first-out
queue with message expiry and at-most-once delivery to only one listener at a time. — Channels documentation

Types of Channels
One type of channel is the routing one, that depending from where the message came, it will route to the proper
consumer. There are three routing channels:

websocket.connect

wesocket.receive

websocket.disconnect

Do you remember in the configuration of the channel layer that we set up routing? So, when a message arrives, it
will be routed by one of the routing channels inside the  routing.py  file. We have three routing channels, one
when the user is trying to start a websocket connection, another one when the user sends a message and a third
for when a client wants to close the connection.

When a message arrives in the  websocket.connect  channel, the message will be sent to
the  ws_connect  consumer, which will process the message.

routing.py

Another type of Channel is the  reply_channel  , which comes with the message object. It is an identifier to
knowledge from where that message came and to know where the consumer should send back its response.

Consumers and Groups
A consumer is a function that will receive a message (websocket request), process it and may return or not a
response.

Let’s start taking a look step by step how our coinpricemonitor was built. First with its  ws_connect  consumer:
Generic consumer

This consumer receives a message and replies with a flag  accept which will tell that the browser should accept
the connection. We can return just a few flags besides  accept , let’s take a look at them:

accept — To accept a new websocket connection.

text — To send a string, but you can import  json  and use  json.dumps()  to send a dictionary.

bytes — Send encrypted data to the frontend, in order to not let others see what you are sending.

In our case, We are using the  accept  key, so when the message is sent, it arrives in the  onOpen  socket method
in the frontend and will print into the console the message “Connected to websocket!”:

Notice that we used the method  send  to send a response to the client, but this method is not from the message
object, it’s from the message’s attribute  reply_channel . This is another type of channel that represents the
user’s channel, to inform which channel send back the response.

As every client has its  reply_channel , when we have to send the new price to each user, we would need to keep
track of the users connected in a list, and send them the new price. But if we wanted to separate users in groups,
like in rooms in a chat in real time, we’d have to keep track of different lists with channels for each room. That’d
be hard to do.

Fortunately, Channels has a way to solve that problem with a data structure called  Group . We create a group
and add in it all channels, so when a update is required, we just need to send the message to the group.

Let’s create a new group called “btc-price” and add the user’s channel to it when he connects to the server:
ws_connect using Group

Now that we have a way to group channels, we actually are going to need one more group, because besides
showing the bitcoin price, we can change to see the  litecoin  (which is another cryptocurrency) price. A group
of channels is going to receive the bitcoin price, and the other one is going to receive the litecoin price.

It is necessary to keep track in which group the user is. To accomplish that, we’re going to store in the user’s
session the name of the group.

Here the  channel_session_user  is imported, It is a channel decorator that gets a Django session for us and
enables it in the message object with the attribute  channel_session . So a new key called  coin-group is added
with the value  btc-price  to keep track in which group the user’s channel is in.

Final ws_connect consumer

Then the new bitcoin price is sent to the frontend. I did it through a periodic task on celery, to make a simple get
request to the bittrex API to get the last bitcoin price and broadcast that price to the  btc-price group.

tasks.py
Here’s the  get_coin_price  helper function:

helpers.py

Now that you know how channels handles a connection, what about the frontend? How to get to
the  ws_connect  consumer? When the page loads, It’s required to create a websocket connection to the backend,
to start receiving the bitcoin current price in real time. After the  load event is triggered,
the  setupWebsocket  function will be called, which will create a WebSocket object with a url, if the project is
running locally, you can use  ws://localhost:8000/ws/ . We setup socket methods for when the connection is
established (onopen) and when a message comes from the backend (onmessage).

main.js

After the creation of a WebSocket object, it will try to connect to its Url. This message will arrive in the channel
layer, which will be routed to the  websocket.connect  channel, leading to the  ws_connect  consumer.

Another flow from the frontend to the backend is when you click in the button to see the  litecoin  price. In
resume, the bitcoin price and icon are being hidden and switched for the litecoin ones. The main part is in the
end: websocket.send() . This is a websocket method that enables data to be sent through it. A flag is being sent to
let the backend knows that the litecoin price is wanted, not bitcoin anymore.
main.js

Since the data is being sent, the message will be routed to the  websocket.receive  channel, leading to
the  ws_receive  consumer.

routing.py

Here we get the data that was sent from the frontend and make an  if statement in order to check either the
user wants the litecoin price or the bitcoin price. If the user wants the litecoin price, we will remove the user
from the group of channels that receives the bitcoin price and put the user’s channel in the group that receives
the litecoin price and change the value of the key  coin-group   ltc-price  to keep track of the user’s channel. In
the other hand, if the client wants the bitcoin price, we put the client’s channel in the  btc-price  group and
discard the channel from the  ltc-price  group and change the value of the key  coin-group  to  btc-price .
consumers.py

After your group is changed, a new value is received in the  onMessage socket method in the frontend.

Depending of which type of coin value was received, it will need to be changed in the proper element.

main.js

The last flow is the disconnection flow. It’s triggered when the browser tab is closed. Doing so,
the  Websocket  object in the frontend will trigger a disconnect event to the backend to finish the websocket
connection.

The message will be routed to the  websocket.disconnect  channel, which will lead to
the  ws_disconnect  consumer.

routing.py
The  ws_disconnect  just removes the user’s channel from the last group that it was in. In order to know which
group it was, we check the value in the  coin-group  stored key is checked.

consumers.py

Conclusion
Channels is a really powerful library for real time applications, as shown, and this was just a small taste of what
it is capable of doing. If you already know Django and have the need to make these types of applications, give
channels a chance and see how it works for you.

That’s basically all you need to know to start with Django channels. If you got interested, here are some links
that might be helpful:

Another amazing tutorial that builds a chat in real time

Channels documentation

Django channels github

You might also like