Whenever you hear the word real-time, the first thing that crosses your mind(If you are a developer) is a Web Socket Connection.
Django doesn’t support web sockets and this is where Django-Channels comes to my rescue.
Below content is for Django-channels version 2.x and Python version 3.x.
What I implemented using Channels?
- The task is to generate notifications and send them in real-time using sockets.
- To reduce complexity, we’ll consider a single user scenario. Suppose a particular notification is to be sent to user X, the main challenge is to identify the number of places from where user X is logged in and then send this notification to all of them.
- For this, I use the concept called Group in Django-channels and I am able to send the notification to all the places without actually knowing the number of places from where X is logged in. Let’s see what is a Group in Django-Channels.
What are groups in Django-Channels?
- A group is a collection of socket connections.
- Each group is identified by a unique name.
- Channels identify a socket connection by providing a unique key to it.
- So when you add a connection to a group, the key of that connection is stored in the group.
- Hence a Group holds all the keys of different socket connections.
- A single socket connection can be added to multiple groups.
- The benefit of a group is that you can broadcast a message to all the connections of a group at once.
- In order to add a connection to group use the group_add method of channel_layer and in order to remove a connection from group use the group_discard method of the channel layer.
- You can broadcast a message to channels in the group using group_send method of the channel layer.
- If you want to know more about, what is channel layer, check here.
How I designed the groups for individual users?
- Whenever a user logs in to my platform, I use Reconnecting WebSocket to open a new socket connection to Django-channels.
- I pass the user authentication token while making a socket connection and in backend use this token to identify the user.
- I have also added a property on my User model to generate a group name for each user. Below is the code for it.
class User(AbstractBaseUser, PermissionsMixin):
"""
Maintain user and its attributes
"""
@property
def group_name(self):
"""
Returns a group name based on the user's id to be used by Django Channels.
Example usage:
user = User.objects.get(pk=1)
group_name = user.group_name
"""
return "user_%s" % self.id
- Now, whenever a new socket connection is made using ReconnectingWebSocket, channels call the connect method of my consumer. Learn more about Consumers here.
- In this connect method, I determine the user, get the group name for that user and finally add the new connection to that group by using the group_add method. For code, see the snippet at the end.
- Now recalling the scenario, if I am to send a notification to a particular user X and X is logged in from 5 tabs, I just need to broadcast it in the group and Django-channels do the needful to send it to all the tabs.
- You might be wondering, how to discard the channel from the group whenever the user closes a tab or logs out. So whenever a user closes a tab socket is automatically disconnected for that tab and if the user logs out, I have explicitly written code that disconnects the active socket connection.
- Whenever a connection closes, Django-channels call the disconnect method of the consumer.
- Within this disconnect method, I use the group_discard method to remove the connection from the group. See below snippet for the code.
So by using Django-Channels, I am able to complete my task of sending the notifications in Real-time.
I have also used Channels to create a real-time messaging app and it’s working seamlessly.
Hope you enjoyed the article. Cheers!
Also read: Getting Started with Two-Factor Authentication in Django Admin Panel