Django で WebSocket と非同期ビューに基づくリアルタイム通信機能を実装する方法

この記事は、Lemony Hug によるHuawei Cloud Community「Django で WebSocket と非同期ビューを使用してリアルタイム通信機能を実装するための完全ガイド」から共有されたものです。

最新の Web アプリケーションでは、リアルタイム通信が不可欠な機能になっています。オンライン チャット、リアルタイム データ更新、リアルタイム通知など、すべてリアルタイム コミュニケーション テクノロジを通じて実現する必要があります。 Django は強力な Web フレームワークとして、さまざまな種類の Web アプリケーションを構築するためのツールを多数提供しています。ただし、リアルタイム通信の観点からは、従来の要求/応答モデルでは明らかにニーズを満たすことができません。この記事では、Django で WebSocket と非同期ビューを活用してリアルタイム通信機能を実装する方法を説明します。

WebSocket の概要

WebSocket は、単一の TCP 接続上で全二重通信を提供するプロトコルです。 HTTP リクエスト/レスポンス モデルとは異なり、WebSocket ではサーバーとクライアント間の継続的な双方向通信が可能になるため、リアルタイムが実現されます。 Django では、サードパーティのライブラリを使用してdjango-channelsWebSocket サポートを実装できます。

非同期ビュー

Django 3.1 では非同期ビューのサポートが導入され、リクエストを非同期に処理するビュー関数を作成できるようになりました。これは、外部リソースからの応答を待つ必要がある長時間実行タスクやリクエストを処理する場合に役立ちます。

WebSocket と非同期ビューの組み合わせ

以下では、ケースを使用して、Django で WebSocket と非同期ビューを組み合わせてリアルタイム通信機能を実装する方法を示します。単純なリアルタイム チャット アプリケーションを開発しているとします。

依存関係をインストールする

まず、django-channelsライブラリをインストールする必要があります。

pip インストール チャネル

設定項目

プロジェクトにアプリケーションsettings.pyを追加します。channels

INSTALLED_APPS = [
    ...
    「チャンネル」、
    ...

次に、routing.pyという新しいファイルを作成し、その中に WebSocket ルートを定義します。

# ルーティング.py

Channels.routing からインポート ProtocolTypeRouter、URLRouter
Channels.auth からインポート AuthMiddlewareStack
django.urls インポート パスから
myapp.consumers から ChatConsumer をインポート

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

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLルーター(
            websocket_urlpatterns
        )
    )、
})

コンシューマの作成

次に、WebSocket 接続を処理するコンシューマを作成します。

# Consumers.py

jsonをインポートする
Channels.generic.websocket からインポート AsyncWebsocketConsumer

クラス ChatConsumer(AsyncWebsocketConsumer):
    非同期デフォルト接続(自己):
        self.room_name = 'チャットルーム'
        self.room_group_name = f'chat_{self.room_name}'

        # チャットルームグループに参加する
        await self.channel_layer.group_add(
            self.room_group_name、
            self.チャンネル名
        )

        self.accept() を待つ

    非同期デフォルト切断(self, close_code):
        # チャットルームグループから退出する
        await self.channel_layer.group_discard(
            self.room_group_name、
            self.チャンネル名
        )

    非同期デフォルト受信(self, text_data):
        text_data_json = json.loads(text_data)
        メッセージ = text_data_json['メッセージ']

        # チャットルームグループにメッセージを送信
        await self.channel_layer.group_send(
            self.room_group_name、
            {
                'タイプ': 'チャットメッセージ',
                'メッセージ': メッセージ
            }
        )

    async def chat_message(self、event):
        メッセージ = イベント['メッセージ']

        #WebSocket接続にメッセージを送信
        await self.send(text_data=json.dumps({
            'メッセージ': メッセージ
        }))

フロントエンドコードを書く

フロントエンド ページでは、JavaScript を使用して WebSocket に接続し、メッセージの送受信を処理する必要があります。

// チャット.js

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

chatSocket.onmessage = function(e) {
    const データ = JSON.parse(e.data);
    const メッセージ = データ['メッセージ'];
    // 受信したメッセージを処理する
    console.log(メッセージ);
};

chatSocket.onclose = function(e) {
    console.error('チャットソケットが予期せず閉じました');
};

document.querySelector('#チャットメッセージ入力').addEventListener('keypress', function(e) {
    if (e.key === 'Enter') {
        const messageInputDom = document.querySelector('#チャットメッセージ入力');
        const メッセージ = messageInputDom.value;
        chatSocket.send(JSON.stringify({
            'メッセージ': メッセージ
        }));
        messageInputDom.value = '';
    }
});

テンプレートに統合する

最後に、JavaScript コードを Django テンプレートに統合します。

<!-- chat.html -->

<!DOCTYPE html>
<html>
<頭>
    <title>チャット</title>
</head>
<本文>
    <textarea id="チャットメッセージ入力"></textarea>
    <script src="{% static 'chat.js' %}"></script>
</body>
</html>

非同期ビューの導入

Django 3.1 より前では、ビュー関数は同期的に実行されていました。つまり、ビュー関数のコードは、HTTP 応答がクライアントに返されるまで実行されていました。ただし、外部 API の呼び出しや複雑な計算の実行など、一部のタスクには時間がかかる場合があります。この場合、ビューを同期するとアプリケーション全体がブロックされ、パフォーマンスの低下が発生します。

この問題を解決するために、Django は Python のasync構文を使用してawait非同期プログラミング パターンをサポートする非同期ビューを導入しました。非同期ビューでは、リクエストの処理中に実行を一時停止し、アプリケーション全体をブロックすることなく IO 操作が完了するのを待つことができます。

WebSocket と非同期ビューの利点を組み合わせる

WebSocket と非同期ビューを組み合わせると、リアルタイム通信アプリケーションのパフォーマンスとスケーラビリティが向上します。同時に通信する接続が多数ある場合、非同期ビューは、1 つの接続のブロックによって他の接続の処理に影響を与えることなく、これらの接続を効果的に管理できます。このようにして、アプリケーションは同時実行性が高い状況にうまく対処し、安定性と効率を維持できます。

リアルタイムチャットアプリケーションの改善

上記の例の基本的なチャット機能に加えて、次のようなリアルタイム チャット アプリケーションの拡張機能を作成することもできます。

  1. ユーザー認証:WebSocket接続時にユーザー認証を行い、ログインしたユーザーのみがチャットルームに入室できるようにします。
  2. チャット ルーム管理: 複数のチャット ルームを作成し、ユーザーが異なるチャット ルームへの参加を選択できるようにします。
  3. メッセージ ストレージ: チャット レコードをデータベースに保存し、ユーザーが切断および再接続した後に履歴メッセージを表示できるようにします。
  4. メッセージ通知: ユーザーが新しいメッセージを受信すると、ブラウザー通知または電子メールを通じて通知されます。
  5. リアルタイムのオンライン ユーザー リスト: 現在のオンライン ユーザー リストを表示し、ユーザーがチャット ルームに出入りするとリアルタイムで更新します。

リアルタイムの位置情報共有

ユーザーが地図上で他のユーザーの位置をリアルタイムで確認できるリアルタイム位置共有アプリケーションを開発しているとします。簡単なコード例を次に示します。

バックエンドコード

# Consumers.py

jsonをインポートする
Channels.generic.websocket からインポート AsyncWebsocketConsumer

クラス LocationConsumer(AsyncWebsocketConsumer):
    非同期デフォルト接続(自己):
        self.room_name = 'location_room'
        self.room_group_name = f'location_{self.room_name}'

        # 位置情報共有ルームに参加する
        await self.channel_layer.group_add(
            self.room_group_name、
            self.チャンネル名
        )

        self.accept() を待つ

    非同期デフォルト切断(self, close_code):
        # ロケーションシェアルームから退出
        await self.channel_layer.group_discard(
            self.room_group_name、
            self.チャンネル名
        )

    非同期デフォルト受信(self, text_data):
        text_data_json = json.loads(text_data)
        緯度 = text_data_json['緯度']
        経度 = text_data_json['経度']

        # 位置情報共有ルームに位置情報を送信
        await self.channel_layer.group_send(
            self.room_group_name、
            {
                'タイプ': 'location_message',
                「緯度」: 緯度、
                「経度」: 経度
            }
        )

    async def location_message(self、event):
        緯度 = イベント['緯度']
        経度 = イベント['経度']

        #WebSocket接続に位置情報を送信
        await self.send(text_data=json.dumps({
            「緯度」: 緯度、
            「経度」: 経度
        }))

フロントエンドコード

// location.js

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

locationSocket.onmessage = function(e) {
    const データ = JSON.parse(e.data);
    const latitude = データ['緯度'];
    const 経度 = データ['経度'];
    // ユーザーの位置を地図上に表示
    updateMap(緯度、経度);
};

locationSocket.onclose = function(e) {
    console.error('ロケーションソケットが予期せず閉じました');
};

関数 sendLocation(緯度, 経度) {
    locationSocket.send(JSON.stringify({
        「緯度」: 緯度、
        「経度」: 経度
    }));
}

この例では、ユーザーはフロントエンド インターフェイスを介して地図上の位置を選択または移動し、WebSocket を介して位置情報をサーバーに送信します。サーバーは位置情報を受信すると、接続されているすべてのユーザーにその情報をブロードキャストします。フロントエンド インターフェイスが位置情報を受信すると、地図上の他のユーザーの位置をリアルタイムで更新します。

このようなリアルタイム位置共有機能は、ソーシャル アプリケーション、リアルタイム ナビゲーション アプリケーション、その他のシナリオに適用して、ユーザーにより良いインタラクティブ エクスペリエンスを提供できます。

リアルタイムのデータ視覚化

さまざまなセンサーからのデータをリアルタイムで表示する必要があるデータ監視システムがあるとします。簡単なコード例を次に示します。

バックエンドコード

# Consumers.py

jsonをインポートする
Channels.generic.websocket からインポート AsyncWebsocketConsumer

クラス SensorDataConsumer(AsyncWebsocketConsumer):
    非同期デフォルト接続(自己):
        self.room_name = 'センサーデータルーム'
        self.room_group_name = f'sensor_data_{self.room_name}'

        # センサーデータ共有ルームに参加する
        await self.channel_layer.group_add(
            self.room_group_name、
            self.チャンネル名
        )

        self.accept() を待つ

    非同期デフォルト切断(self, close_code):
        # センサーデータ共有ルームから退出
        await self.channel_layer.group_discard(
            self.room_group_name、
            self.チャンネル名
        )

    非同期デフォルト受信(self, text_data):
        text_data_json = json.loads(text_data)
        センサーID = text_data_json['センサーID']
        センサー値 = text_data_json['センサー値']

        # センサーデータをセンサーデータ共有ルームに送信
        await self.channel_layer.group_send(
            self.room_group_name、
            {
                'タイプ': 'センサーデータメッセージ',
                'センサー ID': センサー ID、
                'センサー値': センサー値
            }
        )

    async def sensor_data_message(self、event):
        センサーID = イベント['センサーID']
        センサー値 = イベント['センサー値']

        # センサーデータをWebSocket接続に送信
        await self.send(text_data=json.dumps({
            'センサー ID': センサー ID、
            'センサー値': センサー値
        }))

フロントエンドコード

// センサーデータ.js

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

sensorDataSocket.onmessage = function(e) {
    const データ = JSON.parse(e.data);
    const sensorId = データ['センサーID'];
    const sensorValue = データ['センサー値'];
    //センサーデータチャートを更新
    updateChart(センサーID, センサー値);
};

sensorDataSocket.onclose = function(e) {
    console.error('センサー データ ソケットが予期せず閉じられました');
};

関数 sendSensorData(sensorId, sensorValue) {
    sensorDataSocket.send(JSON.stringify({
        'sensor_id': センサーID、
        'センサー値': センサー値
    }));
}

この例では、センサー デバイスは WebSocket 経由でサーバーにリアルタイム データを送信し、サーバーがデータを受信した後、接続されているすべてのユーザーにそのデータをブロードキャストします。リアルタイム データをグラフにリアルタイムで表示します。

このようなリアルタイム データ視覚化機能は、データ監視やリアルタイム分析などのシナリオに適用でき、ユーザーにリアルタイム データ表示および監視機能を提供します。

高度な機能と高度なアプリ

基本的なリアルタイムチャット機能に加え、WebSocketや非同期ビューを組み合わせることで、一連の高度な機能や高度なアプリケーションを実現できます。ここではいくつかの例を示します。

1. リアルタイムの位置情報共有

WebSocket と非同期ビューを使用すると、ユーザー間でのリアルタイムの位置共有を実現できます。ユーザーが移動すると、フロントエンド アプリケーションはユーザーの位置情報をサーバーに送信し、サーバーはこの情報を他のユーザーにブロードキャストします。この機能は、ソーシャル アプリケーション、マップ ナビゲーション アプリケーション、その他のシナリオで非常に役立ちます。

2. リアルタイムデータの視覚化

データ分析とモニタリングの分野では、リアルタイムのデータ視覚化が重要なタスクです。 WebSocket と非同期ビューを通じて、データをリアルタイムでフロントエンドに送信でき、JavaScript チャート ライブラリ (Highcharts、Chart.js など) を使用して、データ変更傾向を表示し、システム ステータスをリアルタイムで監視できます。

3. オンラインでの共同編集

WebSocketと非同期ビューを利用することで、Googleドキュメントのような複数人でのオンライン共同編集機能を実現できます。 1人のユーザーが文書を編集すると、他のユーザーも編集内容の変更をリアルタイムに確認できるため、複数人によるリアルタイムの共同編集が可能になります。

4. リアルタイムゲーム

リアルタイム ゲームでは、リアルタイム通信に対する要求が非常に高くなります。 WebSocket と非同期ビューを組み合わせることで、チェスやカード ゲーム、リアルタイム ストラテジー ゲームなどのリアルタイム マルチプレイヤー オンライン ゲームを実現し、スムーズなゲーム エクスペリエンスを提供します。

5. リアルタイムの検索とフィルタリング

Web サイトやアプリ全体で、ユーザーはリアルタイムでデータを検索およびフィルタリングする必要がある場合があります。 WebSocket と非同期ビューを通じて、検索キーワードやフィルター条件をリアルタイムでサーバーに送信し、サーバーから返される検索結果やフィルターされたデータをリアルタイムで取得できるため、ユーザー エクスペリエンスが向上します。

6. リアルタイム投票とアンケート

オンライン投票やアンケートでは通常、投票結果やアンケートの記入状況にリアルタイムでアクセスする必要があります。 WebSocket と非同期ビューを組み合わせることで、投票結果グラフやアンケート統計をリアルタイムで更新できるため、ユーザーは現在の投票状況やアンケート記入状況をリアルタイムで把握できます。

要約する

この記事では、Django で WebSocket と非同期ビューを使用してリアルタイム通信機能を実装する方法を紹介します。私たちはまず、WebSocket の基本概念と動作原理、およびdjango-channelsDjango で WebSocket をサポートするライブラリの使用方法について学びました。次に、非同期ビューの概念と使用法、および WebSocket と非同期ビューを組み合わせてリアルタイム通信機能を実現する方法について深く検討しました。

簡単なリアルタイム チャット アプリケーションの例を通じて、WebSocket 接続を処理する WebSocket コンシューマ (Consumer) を作成し、非同期ビューを使用して WebSocket 接続内のイベントを処理する方法を示します。また、フロントエンド ページで JavaScript を使用して WebSocket に接続し、受信したメッセージをリアルタイムで処理する方法も紹介しました。

次に、WebSocket と非同期ビューを組み合わせる利点をさらに検討し、リアルタイムの位置情報共有、リアルタイム データの視覚化など、一連の高度な機能と高度なアプリケーションの例を提供します。これらの機能とアプリケーションは、開発者にさまざまなシナリオでのリアルタイム通信のニーズを満たすためのさらなる革新と可能性を提供します。

 

クリックしてフォローし、できるだけ早くHuawei Cloudの新しいテクノロジーについて学びましょう~

 

ライナスは、カーネル開発者がタブをスペースに置き換えるのを防ぐことに自ら取り組みました。 彼の父親はコードを書くことができる数少ないリーダーの 1 人であり、次男はオープンソース テクノロジー部門のディレクターであり、末息子はオープンソース コアです。寄稿者Robin Li: 自然言語 新しいユニバーサル プログラミング言語になるでしょう。オープン ソース モデルは Huawei にますます後れをとっていきます 。一般的に使用されている 5,000 のモバイル アプリケーションを Honmeng に完全に移行するには 1 年かかります。 リッチテキスト エディタ Quill 2.0 リリースされ、機能、信頼性、開発者は「恨みを取り除く ために握手を交わしました。 Laoxiangji のソースはコードではありませんが、その背後にある理由は非常に心温まるものです。Googleは大規模な組織再編を発表しました。
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/u/4526289/blog/11053968