在 Django Channels 2 中向群组发送消息
Sending messages to groups in Django Channels 2
我完全无法使用 Channels 2 进行群组消息传递!我已经按照我能找到的所有教程和文档进行操作,但遗憾的是我还没有找到问题所在。我现在想做的是让一个特定的 URL 在访问时应该向名为 "events".
的组广播一条简单消息
首先,这里是我在 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'
]
接下来,这是我的 EventConsumer,它以非常基本的方式扩展了 JsonWebsocketConsumer。所有这一切都是在收到消息时回显,这很有效!因此,简单的 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
函数,我还错误地认为将组 class 变量添加到我的 EventConsumer 应该会自动将其添加到 that/those 组,它没有!您必须在 connect
class 函数中手动添加组,并在 disconnect
函数中删除组!
问题还在于我的消费者没有指定适当的事件处理程序。在接收警报请求的视图文件中,我将 'type' 设置为 'test'。测试未反映在我的 EventConsumer class 中,因此无法处理该事件。正如第 146 行的多聊天示例 here 中所述,根据发送的事件类型调用辅助函数。所以一个 'event.alarm' 的事件类型在你的消费者中应该有一个对应的 event_alarm
的功能!简单,但没有很好的记录:)。这是最终解决方案的样子:
在consumers.py
中,注意connect中的group_add
和disconnect中的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>')
如果您需要对 question/answer 进行更多说明,请告诉我!干杯!
我有一段时间也遇到过类似的问题,虽然我的 group_send 没有工作的原因是因为 websocket 没有实际连接。
测试重新加载的开发服务器时断开了套接字,因此后续调用未被消费者接收到 运行。刷新前端重新连接套接字,group_send 开始工作。
虽然这并没有直接解决问题,但我希望这可能对某些人有所帮助。
断开连接可能不需要 self.close()
,因为它会自动执行此操作。
也尝试检查 routing.py
文件;我有一个类似的问题,但我通过删除 AuthMiddlewareStack
来修复它(我稍后将其添加回来)然后在我的路径中,我使用了 MyConsumer.as_asgi()
而不是 MyConsumer
.
我完全无法使用 Channels 2 进行群组消息传递!我已经按照我能找到的所有教程和文档进行操作,但遗憾的是我还没有找到问题所在。我现在想做的是让一个特定的 URL 在访问时应该向名为 "events".
的组广播一条简单消息首先,这里是我在 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'
]
接下来,这是我的 EventConsumer,它以非常基本的方式扩展了 JsonWebsocketConsumer。所有这一切都是在收到消息时回显,这很有效!因此,简单的 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
函数,我还错误地认为将组 class 变量添加到我的 EventConsumer 应该会自动将其添加到 that/those 组,它没有!您必须在 connect
class 函数中手动添加组,并在 disconnect
函数中删除组!
问题还在于我的消费者没有指定适当的事件处理程序。在接收警报请求的视图文件中,我将 'type' 设置为 'test'。测试未反映在我的 EventConsumer class 中,因此无法处理该事件。正如第 146 行的多聊天示例 here 中所述,根据发送的事件类型调用辅助函数。所以一个 'event.alarm' 的事件类型在你的消费者中应该有一个对应的 event_alarm
的功能!简单,但没有很好的记录:)。这是最终解决方案的样子:
在consumers.py
中,注意connect中的group_add
和disconnect中的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>')
如果您需要对 question/answer 进行更多说明,请告诉我!干杯!
我有一段时间也遇到过类似的问题,虽然我的 group_send 没有工作的原因是因为 websocket 没有实际连接。
测试重新加载的开发服务器时断开了套接字,因此后续调用未被消费者接收到 运行。刷新前端重新连接套接字,group_send 开始工作。
虽然这并没有直接解决问题,但我希望这可能对某些人有所帮助。
断开连接可能不需要 self.close()
,因为它会自动执行此操作。
也尝试检查 routing.py
文件;我有一个类似的问题,但我通过删除 AuthMiddlewareStack
来修复它(我稍后将其添加回来)然后在我的路径中,我使用了 MyConsumer.as_asgi()
而不是 MyConsumer
.