向 Django Channels 2 中的群组发送消息 [英] Sending messages to groups in Django Channels 2

查看:18
本文介绍了向 Django Channels 2 中的群组发送消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我完全陷入了无法使用频道 2 进行群组消息传递的问题!我已经按照我能找到的所有教程和文档进行了操作,但可惜我还没有找到问题所在.我现在想要做的是拥有一个特定的 URL,当访问该 URL 时,它应该向名为events"的组广播一条简单的消息.

I am completely stuck in that I cannot get group messaging to work with Channels 2! I have followed all tutorials and docs that I could find, but alas I haven't found what the issue seems to be yet. What I am trying to do right now is to have one specific URL that when visited should broadcast a simple message to a group named "events".

首先,以下是我在 Django 中使用的相关和当前设置:

First things first, here are the relevant and current settings that I employ in 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 响应按原样到达,只是组广播不起作用.

Next, here is my EventConsumer, extending the JsonWebsocketConsumer in a very basic way. All this does is echo back when receiving a message, which works! So, the simple send_json response arrives as it should, it is ONLY group broadcasting that does not work.

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: {}
From: {}
Groups: 
                               {}".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 配置:

And here is the URL configurations for the URL that I want to trigger the broadcast:

项目 urls.py

from backend.events import urls as event_urls

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

事件应用 urls.py

Events app urls.py

from backend.events.views import alarm

urlpatterns = [
    url(r'alarm', alarm)
]

最后,应该进行群组广播的视图本身:

And finally, the view itself where the group broadcast should take place:

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 事件.

I found the solution while writing this questions and thought that someone else might also make use of it! Since most of the questions out here are about channels version prior to 2.0 and above, this is how you should handle group_send events in your consumers.

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

The problem did not only lie in how I used the group_send function though, I had wrongly assumed that adding the groups class variable to my EventConsumer should automatically add it to that/those groups, it does NOT! You have to add groups manually in the connect class function and remove groups in the disconnect function!

问题还在于我的消费者没有指定适当的事件处理程序.在接收警报请求的视图文件中,我已将类型"设置为测试".测试未反映在我的 EventConsumer 类中,因此无法处理该事件.如多聊天示例此处中所述编号 146,根据发送的事件类型调用辅助函数.所以一个'event.alarm'的事件类型在你的consumer中应该有一个对应的event_alarm函数!简单,但没有很好的记录:).最终的解决方案如下:

The problem then also lied in that my consumer did not have proper event handlers specified. In my view file, where the alarm request is taken in, I had set the 'type' to 'test'. Test was not reflected in my EventConsumer class so the event could not be processed. As noted in the multichat example here on line number 146, the helper functions get called depending on the type of the event sent. So an event type of 'event.alarm' should have a corresponding function of event_alarm in your consumer! Simple, but not so well documented :). Here is what the final solution looked like:

consumers.py中,注意connect中的group_add和disconnect中的group_discard

In consumers.py, note the group_add in connect and the group_discard in disconnect!

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 调用:

So, the above function events_alarm gets called from the following 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>')

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

Please let me know if you need any more clarifications to the question/answer! Cheers!

这篇关于向 Django Channels 2 中的群组发送消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆