【问题标题】:Sending messages to groups in Django Channels 2在 Django Channels 2 中向组发送消息
【发布时间】:2018-07-29 01:17:15
【问题描述】:

我完全陷入了无法让群组消息与频道 2 一起使用的问题!我已经按照我能找到的所有教程和文档进行操作,但可惜我还没有找到问题所在。我现在要做的是拥有一个特定的 URL,当访问该 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>')

【问题讨论】:

    标签: django redis django-channels


    【解决方案1】:

    我在写这个问题时找到了解决方案,并认为其他人也可以使用它!由于这里的大多数问题都是关于 2.0 及更高版本之前的通道版本,因此您应该在消费者中处理 group_send 事件。

    问题不仅在于我如何使用group_send 函数,我错误地认为将groups 类变量添加到我的EventConsumer 应该自动将它添加到那个/那些组,它不会!您必须在connect 类函数中手动添加组,并在disconnect 函数中删除组!

    问题还在于我的消费者没有指定适当的事件处理程序。在接收警报请求的视图文件中,我已将“类型”设置为“测试”。测试未反映在我的 EventConsumer 类中,因此无法处理该事件。如第 146 行的多聊天示例 here 中所述,根据发送的事件类型调用辅助函数。所以一个事件类型'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>')
    

    如果您需要对问题/答案的更多说明,请告诉我!干杯!

    【讨论】:

    • 是否应该修改 routing.py 中的任何内容?以上只是调用视图而不是 EventConsumer 中的处理程序
    • 你拯救了我的一天!
    【解决方案2】:

    我也遇到过类似的问题,虽然我的 group_send 不起作用的原因是因为 websocket 实际上没有连接。

    在测试重新加载的开发服务器时断开了套接字,因此消费者不会运行后续调用。刷新前端重新连接套接字并且 group_send 开始工作。

    虽然这并不能直接解决这个问题,但我希望这可能对某人有所帮助。

    【讨论】:

    • 是的,也遇到过同样的问题。
    【解决方案3】:

    断开连接可能不需要self.close(),因为它会自动执行此操作。 也尝试检查routing.py文件;我遇到了类似的问题,但我通过删除AuthMiddlewareStack(我稍后添加它)来修复它,然后在我的路径中,我使用MyConsumer.as_asgi() 而不是MyConsumer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-09
      • 2023-03-17
      • 2020-05-13
      • 2018-07-11
      • 2017-01-12
      • 2019-08-15
      • 2019-08-06
      • 1970-01-01
      相关资源
      最近更新 更多