チャンネル2で動作するようにグループメッセージングを取得できないという点で、私は完全に立ち往生しています!私は見つけることができるすべてのチュートリアルとドキュメントに従いましたが、残念ながら、まだ問題が何であるかはわかりませんでした。私が今やろうとしていることは、訪問したときに「イベント」という名前のグループに簡単なメッセージをブロードキャストする特定のURLを持つことです。
まず最初に、Djangoで採用している関連する現在の設定を以下に示します。
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
'hosts': [('localhost', 6379)],
},
}
}
ASGI_APPLICATION = 'backend.routing.application'
INSTALLED_APPS = [
'Django.contrib.admin',
'Django.contrib.auth',
'Django.contrib.contenttypes',
'Django.contrib.sessions',
'Django.contrib.messages',
'Django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'channels',
'channels_redis',
'backend.api'
]
次に、非常に基本的な方法でJsonWebsocketConsumerを拡張するEventConsumerを示します。これは、メッセージを受信したときにエコーバックするだけです。そのため、単純なsend_json応答が到着するはずですが、機能しないのはグループブロードキャストのみです。
class EventConsumer(JsonWebsocketConsumer):
groups = ["events"]
def connect(self):
self.accept()
def disconnect(self, close_code):
print("Closed websocket with code: ", close_code)
self.close()
def receive_json(self, content, **kwargs):
print("Received event: {}\nFrom: {}\nGroups:
{}".format(content,
self.channel_layer,
self.groups))
self.send_json(content)
def event_notification(self, event):
self.send_json(
{
'type': 'test',
'content': event
}
)
次に、ブロードキャストをトリガーするURLのURL構成を示します。
プロジェクトurls.py
from backend.events import urls as event_urls
urlpatterns = [
url(r'^events/', include(event_urls))
]
イベントアプリurls.py
from backend.events.views import alarm
urlpatterns = [
url(r'alarm', alarm)
]
そして最後に、グループブロードキャストが行われるビュー自体:
from Django.shortcuts import HttpResponse
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
def alarm(req):
layer = get_channel_layer()
async_to_sync(layer.group_send)('events', {'type': 'test'})
return HttpResponse('<p>Done</p>')
この質問を書いている間に解決策を見つけ、他の誰かがそれを利用するかもしれないと考えました!ここにある質問のほとんどは2.0以前のバージョンのチャネルに関するものであるため、これはコンシューマでgroup_sendイベントを処理する方法です。
問題はgroup_send
関数の使用方法だけではありませんでしたが、EventConsumerにグループクラス変数を追加すると、そのグループに自動的に追加されると誤って仮定していました。 connect
クラス関数でグループを手動で追加し、disconnect
関数でグループを削除する必要があります!
また、問題は、私のコンシューマーに適切なイベントハンドラーが指定されていないことにもありました。アラーム要求が取り込まれるビューファイルでは、「タイプ」を「テスト」に設定していました。 EventConsumerクラスにテストが反映されなかったため、イベントを処理できませんでした。マルチチャットの例 here の行番号146に記載されているように、ヘルパー関数は送信されたイベントのタイプに応じて呼び出されます。したがって、 'event.alarm'のイベントタイプには、コンシューマでevent_alarm
の対応する関数が必要です。シンプルですが、あまり文書化されていません:)。最終的なソリューションは次のとおりです。
consumers.py
で、接続中のgroup_add
と切断中のgroup_discard
に注意してください!
class EventConsumer(JsonWebsocketConsumer):
def connect(self):
async_to_sync(self.channel_layer.group_add)(
'events',
self.channel_name
)
self.accept()
def disconnect(self, close_code):
print("Closed websocket with code: ", close_code)
async_to_sync(self.channel_layer.group_discard)(
'events',
self.channel_name
)
self.close()
def receive_json(self, content, **kwargs):
print("Received event: {}".format(content))
self.send_json(content)
# ------------------------------------------------------------------------------------------------------------------
# Handler definitions! handlers will accept their corresponding message types. A message with type event.alarm
# has to have a function event_alarm
# ------------------------------------------------------------------------------------------------------------------
def events_alarm(self, event):
self.send_json(
{
'type': 'events.alarm',
'content': event['content']
}
)
したがって、上記の関数events_alarm
は、次のgroup_send
から呼び出されます。
from Django.shortcuts import HttpResponse
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
def alarm(req):
layer = get_channel_layer()
async_to_sync(layer.group_send)('events', {
'type': 'events.alarm',
'content': 'triggered'
})
return HttpResponse('<p>Done</p>')
質問/回答をさらに明確にする必要がある場合はお知らせください!乾杯!
私のgroup_sendが機能しなかった理由は、websocketが実際に接続されていなかったからです。
テスト時にソケットを切断したdevサーバーがリロードされたため、その後の呼び出しはコンシューマーによって実行されませんでした。フロントエンドを更新するとソケットが再接続され、group_sendが機能し始めました。
これは質問に直接対処するものではありませんが、これが誰かの助けになることを願っています。