Chit Chat: Implementation of Chat Server using Django Channels

By StartxLabs
Date 08-05-20
Chit Chat: Implementation of Chat Server using Django Channels
" Chit Chat: Implementation of Chat Server using Django Channels"

 

Today we’re going to talk about Django channels with a small illustration to build a small peer-to-peer chat application and see 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 come 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.

 

Setup

  • First create and activate the virtual environment, i’d recommend using virtualenvwrapper.

  • Install Django using pip install django in your virtualenv.

  • Install Channels and channels-redis in your virtualenv like:
    - pip install channels -pip install channels-redis

 

STEP 1: 

 

File: project/project/settings.py

INSTALLED_APPS = [
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
  'myapp',
  'channels',
.
.
.
# Channels settings
ASGI_APPLICATION = "project.routing.application"
CHANNEL_LAYERS = {
  'default': {
      'BACKEND': 'channels_redis.core.RedisChannelLayer',
      'CONFIG': {
          "hosts": [os.environ.get('REDIS_URL', 'redis://localhost:6379')],
          "symmetric_encryption_keys": [SECRET_KEY],
      },
  },
}

 

STEP 2:

 

File: project/myapp/models.py

class Room(models.Model):
    name = models.TextField()

class Message(models.Model):
    room = models.ForeignKey(Room, related_name='messages',        
                            on_delete=models.CASCADE)
    message = models.TextField()
    timestamp = models.DateTimeField(auto_now_add=True)

STEP 3:

 

File: project/my_app/views.py

def chat_room(request, room_id):
    room, created = Room.objects.get_or_create(id=room_id)
    reversed(room.messages.order_by('-timestamp')[:50])

    return render(request, "chat/room.html", {
        'room': room,
        'messages': messages,
    })

 

STEP 4:

 

Channels

 

Django Channels or Channels  in a nutshell, replaces the “guts” of Django. the request/response cycle — with messages that are sent across channels. Channels allows Django to support WebSockets in a way that’s very similar to traditional HTTP views. Channels also allow for background tasks that run on the same servers as the rest of Django. HTTP requests continue to behave the same as before, but also get routed over channels. Thus, under Channels Django now looks like this: 


 



 

File: project/myapp/consumer.py

from channels.generic.websocket import AsyncWebsocketConsumer
import json

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name=self.scope['url_route']['kwargs']['room_name']
        self.room_group_name='chat_%s' % self.room_name

        # Join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        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']

        # Send message to room group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )

    # Receive message from room group
    async def chat_message(self, event):
        message = event['message']

STEP 5:

 

Next step is to set up the routers for the consumer, the route we set in the routing.py files is what is used by frontend to actually access the consumer.

 

File: project/myapp/routing.py

from django.urls import path
from channels.routing import ProtocolTypeRouter, URLRouter
from .consumers import ChatConsumer


websockets = URLRouter([
  path("ws/chat/<int:room_id>", ChatConsumer, name="chat")
])

And Finally, point the root routing configuration at the project.routing module.

 

File: project/routing.py

from channels.routing import ProtocolTypeRouter, URLRouter
from myapp.routing import websockets


application = ProtocolTypeRouter({
  "websocket": websockets,
})


 

Congratulations! You’ve fully implemented a small chat server using WebSocket and django channels, made it performant by writing it in asynchronous style.



 

Conclusion

 

 

WebSocket support is a huge new feature for Django, but it only scratches the surface of what Channels can do. Remember: Channels is a general-purpose utility for running background tasks. Thus, many features that used to require Celery or Python-RQ could be done using Channels instead. Channels can’t replace dedicated task queues entirely: it has some important limitations, including at-most-once delivery. Still, Channels can make common background tasks much simpler. For example, you could easily use Channels to perform image thumbnailing, send out emails, tweets, or SMSes, run expensive data calculations, and more.

 

 

"We transform your idea into reality, reach out to us to discuss it.

or wanna join our cool team email us at [email protected] or see careers at startxlabs"

subscribe to startxlabs

startxlabs