My Dev Journey: Tackling Real-Time Challenge with Django and the HNG Internship

folafolu

Folafolu Osilaja

Posted on June 29, 2024

My Dev Journey: Tackling Real-Time Challenge with Django and the HNG Internship

I recently tackled a problem to implement real time communication feature in my web application. I'll be sharing how I did it in this article.

My Real Time Communication Challenge

Recently, I had to implement WebSockets in one of my personal projects, something I had never done before. This led me to Django Channels, a package for handling WebSockets in Django.
It was a good learning experience for me as I had to learn a bit of Javascript too. So after a bit of tutorials and research, I was ready to solve my problem.

Django-channels works by creating a consumer and routes in the backend, while Javascript is used in the frontend to open a websocket connection to the specified routes and keeps the connection open so data can be exchanged in real time between the backend and the frontend.

Setting up Django channels

Installing django-channels

  pip install channels

Enter fullscreen mode Exit fullscreen mode

Updating settings.py file

INSTALLED_APPS = [
    ...
    'channels',
]

ASGI_APPLICATION = 'educa.asgi.application'
Enter fullscreen mode Exit fullscreen mode

Creating the web consumer

A consumer handles the Websocket connections

import json
from channels.generic.websocket import AsyncWebsocketConsumer
from django.utils import timezone

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.user = self.scope['user']
        self.id = self.scope['url_route']['kwargs']['course_id']
        self.room_group_name = f'chat_{self.id}'
        # join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        # accept connection
        await self.accept()

      async def disconnect(self, close_code):
        # leave room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    # receive message from WebSocket
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        now = timezone.now()
        # send message to room group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message,
                'user': self.user.username,
                'datetime': now.isoformat(),
            }
        )

    # receive message from room group
    async def chat_message(self, event):
        # send message to WebSocket
        await self.send(text_data=json.dumps(event))
Enter fullscreen mode Exit fullscreen mode

Setting up the routes

from django.urls import re_path
from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/chat/room/(?P<course_id>\d+)/$',
            consumers.ChatConsumer.as_asgi()),
]
Enter fullscreen mode Exit fullscreen mode

Configuring asgi.py file


import os

from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from channels.auth import AuthMiddlewareStack
import chat.routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'educa.settings')

django_asgi_app = get_asgi_application()

application = ProtocolTypeRouter({
    'http': django_asgi_app,
    'websocket': AuthMiddlewareStack(
        URLRouter(chat.routing.websocket_urlpatterns)
       ),
})
Enter fullscreen mode Exit fullscreen mode

Frontend Websocket connection

Finally I wrote the javascript code to open the Websocket connection

const courseId = JSON.parse(
    document.getElementById('course-id').textContent
  );
  const requestUser = JSON.parse(
    document.getElementById('request-user').textContent
  );
  const url = 'wss://' + window.location.host +
              '/ws/chat/room/' + courseId + '/';
  const chatSocket = new WebSocket(url);
a
  chatSocket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    const chat = document.getElementById('chat');

    const dateOptions = {hour: 'numeric', minute: 'numeric', hour12: true};
    const datetime = new Date(data.datetime).toLocaleString('en', dateOptions);
    const isMe = data.user === requestUser;
    const source = isMe ? 'me' : 'other';
    const name = isMe ? 'Me' : data.user;

    chat.innerHTML += '<div class="message ' + source + '">' +
                      '<strong>' + name + '</strong> ' +
                      '<span class="date">' + datetime + '</span><br>' +
                      data.message + '</div>';
  };

  chatSocket.onclose = function(event) {
    console.error('Chat socket closed unexpectedly');
  };

  const input = document.getElementById('chat-message-input');
  const submitButton = document.getElementById('chat-message-submit');

  submitButton.addEventListener('click', function(event) {
    const message = input.value;
    if(message) {
      // send message in JSON format
      chatSocket.send(JSON.stringify({'message': message}));
      // clear input
      input.value = '';
      input.focus();
    }
  });

  input.addEventListener('keypress', function(event) {
    if (event.key === 'Enter') {
      // cancel the default action, if needed
      event.preventDefault();
      // trigger click event on button
      submitButton.click();
    }
  });

  input.focus();
Enter fullscreen mode Exit fullscreen mode

This project was a significant learning experience. Not only did I learn Django Channels, but I also got hands-on with JavaScript.

This is my first attempt at writing an article. I have always wanted to write articles, especially on technical topics relating to programming, but I haven't being able to bring myself to start.
Funny enough, a program I joined has actually pushed me to write this article and publish it. That program is the HNG Internship

What is HNG Internship

This internship is a fast paced boot camp for advanced learners to get in shape for job offers. It provides you with the opportunity to gain real-world experience by working on actual projects for eight weeks and also network with like minded individuals.
You can read more about HNG Internship here. You can also explore the HNG premium network which gives you the opportunity to get access to exclusive opportunities.

Why I joined HNG Internship

I joined the program so I could gain more confidence in applying for jobs seeing that throughout the 8 weeks, I will be working on real project, which is a much needed experience for me right now. I will be pushing myself to limits and boundaries I have never crossed in my programming journey during this program. I have been pushed to write this article so I can be promoted the next stage.

Thank you for reading. I hope to share more about my dev journey and experience during HNG Internship with you.

💖 💪 🙅 🚩
folafolu
Folafolu Osilaja

Posted on June 29, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related