使用django-channels向单个用户发送消息

luk*_*aus 11 django django-channels

我一直在尝试django-channels,包括阅读文档和玩弄例子.

我希望能够通过将新实例保存到数据库来触发向单个用户发送消息.

我的用例是创建一个新的通知(通过芹菜任务),一旦通知保存,将此通知发送给单个用户.

这听起来有可能(来自django-channels docs)

...关键部分是你可以运行代码(以及发送频道)以响应任何事件 - 包括你创建的事件.您可以触发模型保存,其他传入消息或视图和表单内的代码路径.

然而,进一步阅读文档和玩django-channels示例,我无法看到我如何做到这一点.数据绑定和liveblog示例演示了发送到组,但我看不到如何发送给单个用户.

任何建议将不胜感激.

luk*_*aus 16

扩展@ Flip为该特定用户创建组的答案.

在ws_connect函数的python函数中,您可以将该用户添加到一个组中,仅供他们使用:

consumers.py

from channels.auth import channel_session_user_from_http
from channels import Group

@channel_session_user_from_http
def ws_connect(message):
    if user.is_authenticated:
        Group("user-{}".format(user.id)).add(message.reply_channel)
Run Code Online (Sandbox Code Playgroud)

要从python代码向该用户发送消息:

我的view.py

import json
from channels import Group

def foo(user):
    if user.is_authenticated:
        Group("user-{}".format(user.id)).send({
            "text": json.dumps({
            "foo": 'bar'
        })
    })
Run Code Online (Sandbox Code Playgroud)

如果他们已连接,他们将收到该消息.如果用户未连接到websocket,它将无声地失败.

您还需要确保只将一个用户连接到每个用户的组,否则多个用户可能会收到您仅针对特定用户的消息.

看看Django的渠道例子,特别multichat如何实现路由功能,建立在客户端的WebSocket连接和设置django_channels.

请务必查看django渠道文档.

  • 这是实现它的预期方式,还是仅仅是一种解决方法. (2认同)
  • 在实施此解决方案之前,我最担心的是:当组空时,组会自行删除吗?或者每个用户是否会创建一个即使他们永远不会回来也会继续存在的群组? (2认同)

Kar*_*ner 11

Channels 2 中,您可以将self.channel_name连接方法保存在数据库中,该方法是每个用户的特定散列。文档在这里

from asgiref.sync import async_to_sync
from channels.generic.websocket import AsyncJsonWebsocketConsumer
import json

class Consumer(AsyncJsonWebsocketConsumer):
    async def connect(self):
        self.room_group_name = 'room'

        if self.scope["user"].is_anonymous:
            # Reject the connection
            await self.close()
        else:
            # Accept the connection
            await self.channel_layer.group_add(
                self.room_group_name,
                self.channel_name
            )

            await self.accept()

        print( self.channel_name )
Run Code Online (Sandbox Code Playgroud)

最后一行返回类似 specific.WxuYsxLK!owndoeYTkLBw

您可以将这个特定的哈希值保存在用户的表中。


use*_*488 10

小更新,因为组与频道2比他们有渠道不同的工作1.没有Group类了,因为提到这里.

新组API是记录在这里.另见这里.

对我有用的是:

# Required for channel communication
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync


def send_channel_message(group_name, message):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)(
        '{}'.format(group_name),
        {
            'type': 'channel_message',
            'message': message
        }
    )
Run Code Online (Sandbox Code Playgroud)

不要忘记定义一个方法来处理Consumer中的消息类型!

    # Receive message from the group
    def channel_message(self, event):
        message = event['message']

        # Send message to WebSocket
        self.send(text_data=json.dumps({
            'message': message
        }))
Run Code Online (Sandbox Code Playgroud)

  • 以及您如何向特定用户发送消息? (2认同)

Raj*_*mon 5

最好的方法是为该特定用户创建组。当 ws_connect 您可以将该用户添加到Group("%s" % <user>).add(message.reply_channel)

注意:我的 websocket url 是 ws://127.0.0.1:8000/<user>

  • 这也是我想知道的,这种规模的扩展效果如何。 (2认同)