如何在 django 频道中从消费者类外部发送普通 JSON 消息

Posted

技术标签:

【中文标题】如何在 django 频道中从消费者类外部发送普通 JSON 消息【英文标题】:How to send normal JSON message from outside of consumer class in django channels 【发布时间】:2020-10-29 15:58:18 【问题描述】:

我没有使用这个 Django 频道进行聊天,我通过网络套接字通过 DRF AUTH 令牌连接用户

var ws = new WebSocket("ws://127.0.0.1:8008/ws/stream/<token>/")

我想实现如果管理员从后端删除用户,那么在移动前端我会得到用户被删除的自动响应,然后我会调用断开连接方法,这将注销前端的用户,如下所示我正在使用的代码。但无法从消费者外部发送消息。 下面是我的代码:-

class Consumer(AsyncJsonWebsocketConsumer):
    """
    This chat consumer handles websocket connections for chat clients.

    It uses AsyncJsonWebsocketConsumer, which means all the handling functions
    must be async functions, and any sync work (like ORM access) has to be
    behind database_sync_to_async or sync_to_async. For more, read
    http://channels.readthedocs.io/en/latest/topics/consumers.html
    """

    ##### WebSocket event handlers

    async def connect(self):
        """
        Called when the websocket is handshaking as part of initial connection.
        """
        # query_string = dict(self.scope).get('query_string')
        # keys = dict(parse.parse_qs(query_string.decode()))
        self.token_key = self.scope['url_route']['kwargs']['token']
        try:
            if self.token_key:
                # access_token = keys.get('key')
                print(self.token_key)
                self.scope['user'] = await get_user(self.token_key)
                # self.chat_room = self.scope['url_route']['kwargs']['channel']
                await self.accept()
                await self.send_json('code':200, 'message': 'Connection establish successfully', 'error_message': '', 'data':)

        except Exception as ex:
            print("Exception", ex)
            self.scope['user'] = AnonymousUser()
            await self.close()
        

    async def receive_json(self, content):
        """
        Called when we get a text frame. Channels will JSON-decode the payload
        for us and pass it as the first argument.
        """
        # Messages will have a "command" key we can switch on
        try:
            print("this is the content",content)
            command = content.get("command", None)
            #  Under construction

        except ClientError as e:
            # Catch any errors and send it back
            await self.send_json("error": e.code)

    async def user_delete(self):
        await self.send_json('code':400, 'message': 'User deleted', 'error_message': '', 'data':)

    async def disconnect(self, code):
        """
        Called when the WebSocket closes for any reason.
        """
        # Leave all the rooms we are still in
        await self.close()

及以下django模型的代码(执行删除操作时使用信号调用)

from channels.layers import get_channel_layer
class Profile(models.Model):
       ......
       ......
@receiver(post_delete, sender=Profile)
def s3_delete(sender, instance, using, **kwargs):
    try:
        channel_layer = get_channel_layer()
        ?????
        channel_layer.send_json('user deleted')     #Solution which i am trying to apply

    except Exception as ex:
        msg = str(ex)
        print(msg)  

注意:我使用的参考: Send message using Django Channels from outside Consumer class

【问题讨论】:

【参考方案1】:

您好,这是我的解决方案, 首先改变你的消费者的一些东西。 device_info 方法只是一个示例,您可以添加任何内容。

class Consumer(WebsocketConsumer):

    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'something_%s' % self.room_name
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )
        self.accept()

   def device_info(self, event):
        message = event['message']
        self.send(text_data=json.dumps(
            'message': message
        ))

   ***other staff u wanna to add

这是我的频道网址文件。

from django.conf.urls import re_path
from <app_name>.consumer import Consumer

websocket_urlpatterns = [
    re_path(r'url/to/channel/(?P<room_name>\w+)/$', Consumer),
]

这是我发送任何我想要的频道的代码。

from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

room_name = 'outside'

channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(f"something_room_name", "type": "device_info", "message": dict(key="json data that u wanna send outside of consumer"))

【讨论】:

以上是关于如何在 django 频道中从消费者类外部发送普通 JSON 消息的主要内容,如果未能解决你的问题,请参考以下文章

使用来自外部Consumer类的Django Channels发送消息

Django 频道实时聊天保存发送的消息

Django 频道中的消费者

如何从消费者类外部发送 channel_session 数据

我如何订阅消费者并通知他 Django 频道的任何变化

多个类中的 Chromecast 频道