在Django频道2中向组发送消息

时间:2018-02-18 18:59:18

标签: django redis django-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配置:

项目urls.py

from backend.events import urls as event_urls

urlpatterns = [
    url(r'^events/', include(event_urls))
]

活动app 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>')

3 个答案:

答案 0 :(得分:16)

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

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

然后问题还在于我的消费者没有指定正确的事件处理程序。在我的视图文件中,警报请求被带入,我已经设置了&#39;类型&#39;去测试&#39;。测试没有反映在我的EventConsumer类中,因此无法处理该事件。如第146行中的多字幕示例here所述,将根据发送的事件类型调用辅助函数。所以事件类型为'event.alarm&#39;应该在您的消费者中具有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>')

如果您需要对问题/答案进行更多说明,请与我们联系!干杯!

答案 1 :(得分:0)

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

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

虽然这并没有直接解决这个问题,但我希望这可能有助于某些人。

答案 2 :(得分:0)

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