My Dev Journey: Tackling Real-Time Challenge with Django and the HNG Internship
Tags: hng, django, webdev
Published: 2024-06-29 17:28:40

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

```

Updating settings.py file

```
INSTALLED_APPS = [
    ...
    'channels',
]

ASGI_APPLICATION = 'educa.asgi.application'
```

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

### 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()),
]
```

### 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)
       ),
})
```


### 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();
```
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](https://hng.tech/internship). You can also explore the [HNG premium network](https://hng.tech/premium) 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.