Reader small image

You're reading from  Django 5 By Example - Fifth Edition

Product typeBook
Published inApr 2024
PublisherPackt
ISBN-139781805125457
Edition5th Edition
Right arrow
Author (1)
Antonio Melé
Antonio Melé
author image
Antonio Melé

Antonio Melé has been crafting Django projects since 2006, for clients spanning multiple industries. He is Engineering Director at Backbase, a leading global fintech firm dedicated to facilitating the digital transformation of financial institutions. He co-founded Nucoro, a digital wealth management platform. In 2009 Antonio founded Zenx IT, a company specialized in developing digital products. He has been working as CTO and consultant for several tech-centric startups. He has also managed development teams building projects for large enterprise clients. He has an MSc in Computer Science from Universidad Pontificia Comillas and completed the Advanced Management Program at MIT Sloan. His father inspired his passion for computers and coding.
Read more about Antonio Melé

Right arrow

Building a Chat Server

In the previous chapter, you created a RESTful API for your project that provides a programmable interface for your application.

In this chapter, you will develop a chat server for students using Django Channels, enabling students to engage in real-time messaging within course chat rooms. You will learn how to build real-time applications through asynchronous programming with Django Channels. By serving your Django project through Asynchronous Server Gateway Interface (ASGI), and implementing asynchronous communication, you will enhance the responsiveness and scalability of your server. Additionally, you will persist chat messages into the database, building a comprehensive chat history and enriching the user experience and functionality of the chat application.

In this chapter, you will:

  • Add Channels to your project
  • Build a WebSocket consumer and appropriate routing
  • Implement a WebSocket client
  • Enable a channel layer with...

Functional overview

Figure 16.1 shows a representation of the views, templates, and functionalities that will be built in this chapter:

Figure 16.1: Diagram of functionalities built in this chapter

In this chapter, you will implement the course_chat_room view in the chat application. This view will serve the template that displays the chat room for a given course. The latest chat messages will be displayed when a user joins a chat room. You will use JavaScript to establish a WebSocket connection in the browser, and you will build the ChatConsumer WebSocket consumer to handle WebSocket connections and to exchange messages. You will use Redis to implement the channel layer that allows broadcasting messages to all users in the chat room.

The source code for this chapter can be found at https://github.com/PacktPublishing/Django-5-by-example/tree/main/Chapter16.

All Python modules used in this chapter are included in the requirements.txt file in the source code that...

Creating a chat application

You are going to implement a chat server to provide students with a chat room for each course. Students enrolled in a course will be able to access the course chat room and exchange messages in real time. You will use Channels to build this functionality. Channels is a Django application that extends Django to handle protocols that require long-running connections, such as WebSockets, chatbots, or MQTT (a lightweight publish/subscribe message transport commonly used in Internet of Things (IoT) projects).

Using Channels, you can easily implement real-time or asynchronous functionalities into your project in addition to your standard HTTP synchronous views. You will start by adding a new application to your project. The new application will contain the logic for the chat server.

You can the documentation for Django Channels at https://channels.readthedocs.io/.

Let’s start implementing the chat server. Run the following command from the...

Real-time Django with Channels

You are building a chat server to provide students with a chat room for each course. Students enrolled in a course will be able to access the course chat room and exchange messages. This functionality requires real-time communication between the server and the client.

A standard HTTP request/response model doesn’t work here because you need the browser to receive notifications as soon as new messages arrive. There are several ways you could implement this feature, using AJAX polling or long polling in combination with storing the messages in your database or Redis. However, there is no efficient way to implement real-time communication using a standard synchronous web application.

You need asynchronous communication, which allows real-time interactions, where the server can push updates to the client as soon as new messages arrive without the client needing to request updates periodically. Asynchronous communication also comes with other...

Installing Channels and Daphne

You are going to add Channels to your project and set up the required basic ASGI application routing for it to manage HTTP requests.

Install Channels in your virtual environment with the following command:

python -m pip install -U 'channels[daphne]==4.1.0'

This will simultaneously install Channels along with the Daphne ASGI application server. An ASGI server is necessary for handling asynchronous requests, and we choose Daphne for its simplicity and compatibility, as it comes bundled with Channels.

Edit the settings.py file of the educa project and add daphne to the beginning of the INSTALLED_APPS setting as follows:

INSTALLED_APPS = [
    'daphne',
    # ...
]

When daphne is added to the INSTALLED_APPS setting, it takes control over the runserver command, replacing the standard Django development server. This will allow you to serve asynchronous requests during development. Besides handling URL routing to...

Writing a consumer

Consumers are the equivalent of Django views for asynchronous applications. As mentioned, they handle WebSockets in a very similar way to how traditional views handle HTTP requests. Consumers are ASGI applications that can handle messages, notifications, and other things. Unlike Django views, consumers are built for long-running communication. URLs are mapped to consumers through routing classes that allow you to combine and stack consumers.

Let’s implement a basic consumer that can accept WebSocket connections and echoes every message it receives from the WebSocket back to it. This initial functionality will allow the student to send messages to the consumer and receive back the messages it sends.

Create a new file inside the chat application directory and name it consumers.py. Add the following code to it:

import json
from channels.generic.websocket import WebsocketConsumer
class ChatConsumer(WebsocketConsumer):
    def connect(self):
     ...

Routing

You need to define a URL to route connections to the ChatConsumer consumer you have implemented. Channels provides routing classes that allow you to combine and stack consumers to dispatch based on what the connection is. You can think of them as the URL routing system of Django for asynchronous applications.

Create a new file inside the chat application directory and name it routing.py. Add the following code to it:

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

In this code, you map a URL pattern with the ChatConsumer class that you defined in the chat/consumers.py file. There are some details that are worth reviewing:

  • You use Django’s re_path() to define the path with a regular expression instead of path(). Channels’ URL routing may not function correctly with path() routes if...

Implementing the WebSocket client

So far, you have created the course_chat_room view and its corresponding template for students to access the course chat room. You have implemented a WebSocket consumer for the chat server and tied it with URL routing. Now, you need to build a WebSocket client to establish a connection with the WebSocket in the course chat room template and be able to send/receive messages.

You are going to implement the WebSocket client with JavaScript to open and maintain a connection in the browser, and you will interact with the Document Object Model (DOM) using JavaScript.

You will perform the following tasks related to the WebSocket client:

  1. Open a WebSocket connection with the server when the page is loaded.
  2. Add messages to an HTML container when data is received through the WebSocket.
  3. Attach a listener to the submit button to send messages through the WebSocket when the user clicks the SEND button or presses the Enter key.
  4. ...

Enabling a channel layer

Channel layers allow you to communicate between different instances of an application. A channel layer is the transport mechanism that allows multiple consumer instances to communicate with each other and with other parts of Django.

In your chat server, you plan to have multiple instances of the ChatConsumer consumer for the same course chat room. Each student who joins the chat room will instantiate the WebSocket client in their browser, and that will open a connection with an instance of the WebSocket consumer. You need a common channel layer to distribute messages between consumers.

Channels and groups

Channel layers provide two abstractions to manage communications: channels and groups:

  • Channel: You can think of a channel as an inbox where messages can be sent or as a task queue. Each channel has a name. Messages are sent to a channel by anyone who knows the channel name and then given to consumers listening on that channel.
  • ...

Modifying the consumer to be fully asynchronous

The ChatConsumer you have implemented inherits from the synchronous base class WebsocketConsumer. Synchronous consumers operate in a way that each request must be processed in sequence, one after the other. Synchronous consumers are convenient for accessing Django models and calling regular synchronous I/O functions. However, asynchronous consumers perform better because of their ability to perform non-blocking operations, moving to another task without waiting for the first operation to complete. They don’t require additional threads when handling requests, thus reducing wait times and increasing the ability to scale to more users and requests simultaneously.

Given that you are already using the asynchronous channel layer functions, you can seamlessly rewrite the ChatConsumer class to make it asynchronous.

Edit the consumers.py file of the chat application and implement the following changes:

import json
from channels...

Persisting messages into the database

Let’s enhance the chat application by adding message persistence. We will develop functionality to store messages in the database, allowing us to present a chat history to users when they join a chat room. This feature is essential for real-time applications, where it’s necessary to display both current and previously generated data. For example, consider a stock trading application: upon logging in, users should see not only the current stock values but also the historical values from the time the stock market opened.

To implement the chat history functionality, we will follow these steps:

  1. We will create Django model to store chat messages and add it to the administration site.
  2. We will modify the WebSocket consumer to persist messages.
  3. We will retrieve the chat history to display the latest messages when users enter a chat room.

Let’s start by creating the message model.

Creating a...

Integrating the chat application with existing views

The chat server is now fully implemented, and students enrolled in a course can communicate with each other. Let’s add a link for students to join the chat room for each course.

Edit the students/course/detail.html template of the students application and add the following <h3> HTML element code at the bottom of the <div class="contents"> element:

<div class="contents">
  ...
  <h3>
    <a href="{% url "chat:course_chat_room" object.id %}">
      Course chat room
    </a>
  </h3>
</div>

Open the browser and access any course that the student is enrolled in to view the course contents. The sidebar will now contain a Course chat room link that points to the course chat room view. If you click on it, you will enter the chat room:

Figure 16.13: The course detail page, including a link to the course chat room

Congratulations...

Summary

In this chapter, you learned how to create a chat server using Channels. You implemented both a WebSocket consumer and a client. By enabling communication through a channel layer with Redis and modifying the consumer to be fully asynchronous, you improved the responsiveness and scalability of your application. Additionally, you implemented chat message persistence, providing a robust and user-friendly experience and maintaining chat history for users over time. The skills you learned in this chapter will help you in any future implementations of asynchronous real-time functionalities.

The next chapter will teach you how to build a production environment for your Django project using NGINX, uWSGI, and Daphne with Docker Compose. You will also learn how to implement custom middleware for request/response processing across your entire application, and how to develop custom management commands, which enable you to automate tasks and execute them via the command line.

...

Additional resources

The following resources provide additional information related to the topics covered in this chapter:

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Django 5 By Example - Fifth Edition
Published in: Apr 2024Publisher: PacktISBN-13: 9781805125457
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Antonio Melé

Antonio Melé has been crafting Django projects since 2006, for clients spanning multiple industries. He is Engineering Director at Backbase, a leading global fintech firm dedicated to facilitating the digital transformation of financial institutions. He co-founded Nucoro, a digital wealth management platform. In 2009 Antonio founded Zenx IT, a company specialized in developing digital products. He has been working as CTO and consultant for several tech-centric startups. He has also managed development teams building projects for large enterprise clients. He has an MSc in Computer Science from Universidad Pontificia Comillas and completed the Advanced Management Program at MIT Sloan. His father inspired his passion for computers and coding.
Read more about Antonio Melé