How to implement real-time communication functions based on WebSockets and asynchronous views in Django

This article is shared from the Huawei Cloud Community " A Complete Guide to Implementing Real-Time Communication Functions Using WebSockets and Asynchronous Views in Django " by Lemony Hug.

In modern web applications, real-time communication has become an essential feature. Whether it is online chat, real-time data updates or real-time notifications, they all need to be achieved through real-time communication technology. As a powerful web framework, Django provides many tools to build various types of web applications. However, in terms of real-time communication, the traditional request-response model obviously cannot meet the needs. In this article, we will explore how to leverage WebSockets and asynchronous views in Django to implement real-time communication capabilities.

Introduction to WebSockets

WebSockets is a protocol that provides full-duplex communication over a single TCP connection. Unlike the HTTP request-response model, WebSockets allow continuous two-way communication between the server and client, thus achieving real-time. In Django, we can use third-party libraries django-channelsto implement WebSocket support.

asynchronous view

Django 3.1 introduced support for asynchronous views, allowing us to write view functions that handle requests asynchronously. This is useful for handling long-running tasks or requests that require waiting for a response from an external resource.

Combining WebSockets with asynchronous views

Below we will use a case to demonstrate how to combine WebSockets and asynchronous views in Django to implement real-time communication functions. Let's say we are developing a simple real-time chat application.

Install dependencies

First, we need to install django-channelsthe library:

pip install channels

Configuration items

In the project settings.py, add channelsthe application:

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

Then, create a routing.pynew file called and define the WebSocket route in it:

# routing.py

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

websocket_urlpatterns = [
    path('ws/chat/', ChatConsumer.as_asgi()),
]

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter(
            websocket_urlpatterns
        )
    ),
})

Create Consumer

Next, we create a Consumer to handle WebSocket connections:

# consumers.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = 'chat_room'
        self.room_group_name = f'chat_{self.room_name}'

        # Join the chat 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 the chat room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

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

    async def chat_message(self, event):
        message = event['message']

        #Send message to WebSocket connection
        await self.send(text_data=json.dumps({
            'message': message
        }))

Write front-end code

In the front-end page, we need to use JavaScript to connect to WebSocket and handle the sending and receiving of messages:

// chat.js

const chatSocket = new WebSocket('ws://localhost:8000/ws/chat/');

chatSocket.onmessage = function(e) {
    const data = JSON.parse(e.data);
    const message = data['message'];
    // Process the received message
    console.log(message);
};

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

document.querySelector('#chat-message-input').addEventListener('keypress', function(e) {
    if (e.key === 'Enter') {
        const messageInputDom = document.querySelector('#chat-message-input');
        const message = messageInputDom.value;
        chatSocket.send(JSON.stringify({
            'message': message
        }));
        messageInputDom.value = '';
    }
});

Integrate into template

Finally, we integrate the JavaScript code in the Django template:

<!-- chat.html -->

<!DOCTYPE html>
<html>
<head>
    <title>Chat</title>
</head>
<body>
    <textarea id="chat-message-input"></textarea>
    <script src="{% static 'chat.js' %}"></script>
</body>
</html>

Introducing asynchronous views

Prior to Django 3.1, view functions were executed synchronously, which meant that the code in a view function was executed until an HTTP response was returned to the client. However, some tasks can be time-consuming, such as calling external APIs or performing complex calculations. In this case, synchronizing the view blocks the entire application, causing performance degradation.

To solve this problem, Django introduced asynchronous views, which use Python's asyncsyntax awaitto support asynchronous programming patterns. Asynchronous views allow execution to be suspended while a request is being processed, waiting for the IO operation to complete without blocking the entire application.

Combining the advantages of WebSockets and asynchronous views

Combining WebSockets with asynchronous views can make real-time communication applications have higher performance and scalability. When there are a large number of connections communicating at the same time, asynchronous views can effectively manage these connections without affecting the processing of other connections due to the blocking of one connection. In this way, the application can better cope with high concurrency situations and maintain stability and efficiency.

Improve real-time chat application

In addition to the basic chat functionality in the above example, we can also make some extensions to the real-time chat application, such as:

  1. User authentication: Perform user authentication when connecting to WebSocket to ensure that only logged-in users can enter the chat room.
  2. Chat room management: Create multiple chat rooms and allow users to choose to join different chat rooms.
  3. Message storage: Save chat records to the database so that users can view historical messages after disconnecting and reconnecting.
  4. Message notification: Implement the message notification function. When the user receives a new message, the user will be reminded through a browser notification or email.
  5. Real-time online user list: Displays the current online user list and updates it in real time when the user enters or leaves the chat room.

Real-time location sharing

Suppose we are developing a real-time location sharing application where users can see the locations of other users on a map in real time. Here is a simple example code:

backend code

# consumers.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer

class LocationConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = 'location_room'
        self.room_group_name = f'location_{self.room_name}'

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

        await self.accept()

    async def disconnect(self, close_code):
        # Leave location shared room
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        latitude = text_data_json['latitude']
        longitude = text_data_json['longitude']

        # Send location information to the geo-location shared room
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'location_message',
                'latitude': latitude,
                'longitude': longitude
            }
        )

    async def location_message(self, event):
        latitude = event['latitude']
        longitude = event['longitude']

        #Send location information to WebSocket connection
        await self.send(text_data=json.dumps({
            'latitude': latitude,
            'longitude': longitude
        }))

front-end code

// location.js

const locationSocket = new WebSocket('ws://localhost:8000/ws/location/');

locationSocket.onmessage = function(e) {
    const data = JSON.parse(e.data);
    const latitude = data['latitude'];
    const longitude = data['longitude'];
    //Show user location on map
    updateMap(latitude, longitude);
};

locationSocket.onclose = function(e) {
    console.error('Location socket closed unexpectedly');
};

function sendLocation(latitude, longitude) {
    locationSocket.send(JSON.stringify({
        'latitude': latitude,
        'longitude': longitude
    }));
}

In this example, the user selects or moves a location on the map through the front-end interface, and then sends the location information to the server via WebSocket. After the server receives the location information, it broadcasts it to all connected users. After the front-end interface receives the location information, it updates the locations of other users on the map in real time.

Such real-time location sharing function can be applied in social applications, real-time navigation applications and other scenarios to provide users with a better interactive experience.

Real-time data visualization

Suppose we have a data monitoring system that needs to display data from various sensors in real time. Here is a simple example code:

backend code

# consumers.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer

class SensorDataConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = 'sensor_data_room'
        self.room_group_name = f'sensor_data_{self.room_name}'

        # Join the sensor data sharing room
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, close_code):
        # Leave the sensor data sharing room
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        sensor_id = text_data_json['sensor_id']
        sensor_value = text_data_json['sensor_value']

        # Send sensor data to the sensor data sharing room
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'sensor_data_message',
                'sensor_id': sensor_id,
                'sensor_value': sensor_value
            }
        )

    async def sensor_data_message(self, event):
        sensor_id = event['sensor_id']
        sensor_value = event['sensor_value']

        # Send sensor data to WebSocket connection
        await self.send(text_data=json.dumps({
            'sensor_id': sensor_id,
            'sensor_value': sensor_value
        }))

front-end code

// sensor_data.js

const sensorDataSocket = new WebSocket('ws://localhost:8000/ws/sensor_data/');

sensorDataSocket.onmessage = function(e) {
    const data = JSON.parse(e.data);
    const sensorId = data['sensor_id'];
    const sensorValue = data['sensor_value'];
    //Update sensor data chart
    updateChart(sensorId, sensorValue);
};

sensorDataSocket.onclose = function(e) {
    console.error('Sensor data socket closed unexpectedly');
};

function sendSensorData(sensorId, sensorValue) {
    sensorDataSocket.send(JSON.stringify({
        'sensor_id': sensorId,
        'sensor_value': sensorValue
    }));
}

In this example, the sensor device sends real-time data to the server through WebSocket. After the server receives the data, it broadcasts it to all connected users. After the front-end interface receives the data, it uses a JavaScript chart library to display the real-time data in a chart in real time.

Such real-time data visualization function can be applied in scenarios such as data monitoring and real-time analysis, providing users with real-time data display and monitoring functions.

Advanced features and advanced apps

In addition to basic real-time chat functions, a series of advanced functions and advanced applications can be achieved by combining WebSockets and asynchronous views. Here are some examples:

1. Real-time location sharing

Using WebSocket and asynchronous views, real-time location sharing between users can be achieved. As the user moves, the front-end application can send the user's location information to the server, which then broadcasts this information to other users. This function is very useful in social applications, map navigation applications and other scenarios.

2. Real-time data visualization

In the field of data analysis and monitoring, real-time data visualization is an important task. Through WebSocket and asynchronous views, data can be transmitted to the front end in real time, and JavaScript chart libraries (such as Highcharts, Chart.js, etc.) can be used to display data change trends and monitor system status in real time.

3. Online collaborative editing

Using WebSocket and asynchronous views, you can realize multi-person online collaborative editing functions, similar to Google Docs. When one user edits a document, other users can see the changes in the edited content in real time, thus enabling real-time collaborative editing by multiple people.

4. Real-time gaming

Real-time games have very high demands for real-time communication. Combining WebSocket and asynchronous views can realize real-time multiplayer online games, such as chess and card games, real-time strategy games, etc., providing a smooth gaming experience.

5. Real-time search and filtering

Across websites and apps, users may need to search and filter data in real time. Through WebSocket and asynchronous views, you can send search keywords or filter conditions to the server in real time, and obtain the search results or filtered data returned by the server in real time, thereby improving the user experience.

6. Real-time voting and questionnaires

Online voting and questionnaires usually require real-time access to voting results or questionnaire filling status. Combining WebSocket and asynchronous views, voting result charts or questionnaire statistics can be updated in real time, allowing users to understand the current voting situation or questionnaire filling progress in real time.

Summarize

This article introduces how to use WebSockets and asynchronous views in Django to implement real-time communication functions. We first learned about the basic concepts and working principles of WebSockets, and django-channelshow to use libraries to support WebSockets in Django. Next, we deeply explored the concept and usage of asynchronous views, and how to combine WebSockets and asynchronous views to achieve real-time communication functions.

Through a simple real-time chat application example, we demonstrate how to create a WebSocket consumer (Consumer) to handle WebSocket connections and use asynchronous views to handle events in WebSocket connections. We also introduced how to use JavaScript in the front-end page to connect to WebSocket and process the received messages in real time.

We then further explore the advantages of combining WebSockets and asynchronous views, and provide a series of advanced features and examples of advanced applications, including real-time location sharing, real-time data visualization, etc. These functions and applications can provide developers with more innovations and possibilities to meet real-time communication needs in different scenarios.

 

Click to follow and learn about Huawei Cloud’s new technologies as soon as possible~

 

Linus took it upon himself to prevent kernel developers from replacing tabs with spaces. His father is one of the few leaders who can write code, his second son is the director of the open source technology department, and his youngest son is an open source core contributor. Robin Li: Natural language will become a new universal programming language. The open source model will fall further and further behind Huawei: It will take 1 year to fully migrate 5,000 commonly used mobile applications to Hongmeng. Java is the language most prone to third-party vulnerabilities. Rich text editor Quill 2.0 has been released with features, reliability and developers. The experience has been greatly improved. Ma Huateng and Zhou Hongyi shook hands to "eliminate grudges." Meta Llama 3 is officially released. Although the open source of Laoxiangji is not the code, the reasons behind it are very heart-warming. Google announced a large-scale restructuring
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4526289/blog/11053968