一尘不染

将消息发送到Django Channels 2中的组

redis

我完全陷入困境,因为我无法让群组消息与Channels
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>')

阅读 593

收藏
2020-06-20

共1个答案

一尘不染

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

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

然后,问题还在于我的使用者没有指定适当的事件处理程序。在接收警报请求的视图文件中,我已将“类型”设置为“测试”。测试未反映在我的EventConsumer类中,因此无法处理该事件。正如multichat例子说明这里的行号146,辅助函数得到取决于事件,将会发出的类型调用。因此,事件类型“
event.alarm” event_alarm在您的使用者中应该具有相应的功能!很简单,但是记录的不是很好:)。最终的解决方案如下所示:

在中consumers.py,请注意group_addin连接和group_discardin断开!

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>')

如果您需要进一步澄清问题/答案,请告诉我!干杯!

2020-06-20