如何使用 Django Channels 3.0.0 向所有消费者发送消息?
Posted
技术标签:
【中文标题】如何使用 Django Channels 3.0.0 向所有消费者发送消息?【英文标题】:How to send a message to all consumers using Django Channels 3.0.0? 【发布时间】:2020-11-04 23:22:10 【问题描述】:我正在尝试开发一个界面,其中包含一个显示所有活动用户的部分。因此,当用户连接到 WebSocket 时,我想向所有连接的消费者发送数据。
目前,我编写了一个代码,当用户连接时,它只向连接的用户发送数据。我想以某种方式将消息发送给所有活跃的用户/消费者。
这是我的 WebSocket 处理程序/视图的路径
path('test_ws/', websocket.TestConsumer.as_asgi()),
这里是处理程序
class NewsMentionConsumer(AsyncWebsocketConsumer):
groups = ["newsmention1"]
channel_name = 'news_mention'
active_users = []
async def connect(self):
await self.channel_layer.group_add(self.groups[0], self.channel_name)
await self.channel_layer.group_send(self.groups[0],
'type': 'send_updates',
'text': json.dumps(
'id': self.scope['user'].id,
'username': self.scope['user'].username,
'active_users': self.active_users
)
)
await self.accept()
self.active_users.append(self.scope['user'])
async def send_updates(self, event):
# TODO: Make this send to all users/consumers
await self.send(event["text"])
我在理解 django.channels 文档中的示例时遇到了问题,并尝试使用 send_group
函数,但它并没有真正起作用。有什么建议吗?
编辑:将所有用户添加到具有唯一名称的同一组中。
async def connect(self):
await self.channel_layer.group_add(self.groups[0], self.unique_name());
await self.channel_layer.group_send(self.groups[0], ... );
group_send
仍然只将消息发送给请求的用户。
编辑2:添加init函数后。
现在,我有一个 channel_name,但是当我尝试将数据发送给组中的所有消费者时出现新错误:
class NewsMentionConsumer(AsyncWebsocketConsumer):
group = "newsmention1"
active_users = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
async def connect(self):
await self.channel_layer.group_add(
self.group,
self.channel_name,
)
await self.channel_layer.group_send(self.group,
'type': 'send_updates',
'id': self.scope['user'].id,
'username': self.scope['user'].username,
'some_data_to_all_clients': some_data_to_all_clients()
)
async def disconnect(self, close_code):
await self.channel_layer.group_discard(self.group, self.channel_name)
async def send_updates(self, event):
await self.channel_layer.send_group(self.group, event)
'RedisChannelLayer' object has no attribute 'send_group'
有什么建议吗?
编辑 3:
async def connect(self):
await self.accept()
await self.channel_layer.group_add(
self.group,
self.channel_name,
)
self.active_users.append(
'id': self.scope['user'].id,
'username': self.scope['user'].username
)
await self.channel_layer.group_send(self.group,
'type': 'send_updates',
'id': self.scope['user'].id,
'username': self.scope['user'].username,
'some_data_to_all_clients': some_data_to_all_clients()
)
async def send_updates(self, event):
await self.send(json.dumps(event))
【问题讨论】:
多余的__init__
方法有什么原因吗?除非需要,否则不应覆盖它。您仍然收到频道名称的空错误吗?您发布的错误是不同的,并且非常不言自明。您应该在send_updates
方法中调用channel_layer.send(...)
而不是send_group
,因为没有这样的方法。请参考文档中的教程
channel_layer.send(...)
是否应该将数据发送给同一组中的所有消费者?
不,它没有,self.channel_layer.group_send
有,而且你已经在使用它了。 group_send
将消息广播到组中的每个通道,每个通道都包含 send_updates
方法,该方法现在通过 websocket 连接将消息发送到下游消费者。这就是为什么您需要send
方法将其发送给客户端
我将更新我的代码以显示我如何在连接函数中使用.group_send
和在send_updates
函数中使用.send
(正如您所说),它仍然将消息发送到请求的仅限消费者。
我的错,它不应该是channel_layer.send
,而是self.send
,因为你没有通过通道层发送。如果您按照文档中的聊天教程进行操作,这将非常有帮助,因为他们已经在channels.readthedocs.io/en/stable/tutorial/part_3.html 中正确执行了这些操作
【参考方案1】:
This is a bug 的 Django 频道 3.0.0
。它已在3.0.1
中修复。
【讨论】:
正确,我在一周内修复错误的两个版本之间的一天内开始使用 Django 频道。【参考方案2】:您不应设置静态频道名称,因为它用于标识频道,因此必须是唯一的。通常的做法是使用 Django Channels 生成的频道名称。 关于向所有连接的用户发送事件,您只需要有一个组,在他们连接时将所有通道添加到该组,然后在那里发送消息。除了频道名称部分外,您所做的看起来已经很相似了。
【讨论】:
我再次尝试将所有用户添加到相同的组名和唯一的频道名称中,但 send_group 函数仍然只将消息发送给请求的用户。 您使用的是哪个通道层?您确定其他用户已连接吗?顺便说一句,不要创建自己的频道名称,使用 Django 频道分配的名称。如果您想识别用户,请为他创建一个单独的组。无论如何,这种方法更好,因为您将能够识别来自同一用户的多个连接 目前,我确信我为每个渠道/消费者使用了唯一的名称,并且它们都在同一个组中。当我尝试 self.channel_name 时,“使用由 Django 频道分配的频道”是什么意思,它总是未定义。我还是卡住了。 那么你的代码有问题。 self.channel_name 由 Django Channels 填充,通常保持原样。如果出现错误,请使用它并发布您的代码和堆栈跟踪。另外,您使用的是哪个通道层?可以显示 CHANNEL_LAYER 设置吗? 抱歉,我忘记了消费者类中的 init,现在我为每个消费者设置了一个频道名称。以上是关于如何使用 Django Channels 3.0.0 向所有消费者发送消息?的主要内容,如果未能解决你的问题,请参考以下文章