【问题标题】:How can I add a user whose ID I know to a Django Channels channel_layer group?如何将我知道其 ID 的用户添加到 Django Channels channel_layer 组?
【发布时间】:2019-12-20 10:34:21
【问题描述】:

我正在使用来自 django-channels 的 websocket 编写一个 web 应用程序。其中:

  1. 客户用户可以向商店用户下订单。
  2. 当用户通过他们的通讯器请求订单时,我会使用订单的 ID 创建一个渠道组。
  3. 与此订单相关的商店也应添加到此渠道组。 这是我正在努力实现的目标。

这个逻辑可以看我下面的pytest:

async def test_store_is_added_to_order_group_on_create(self, settings):
    customer = await create_customer()
    store = await create_store()
    product = await create_product(store=store)

    store_communicator = await auth_connect(store)

    # Log in as customer and create order
    customer_communicator = await auth_connect(user)
    await communicator.send_json_to({
        'type': 'create.order',
        'data': {
            'product': str(product.id),
            'customer': user.id
        }
    })
    response = await communicator.receive_json_from()
    data = response.get('data')
    await communicator.disconnect()

    # Send JSON message to new order's group.
    order_id = data['id']
    message = {
        'type': 'echo.message',
        'data': 'This is a test message.'
    }
    channel_layer = get_channel_layer()
    await channel_layer.group_send(order_id, message=message)

    # Store should receive JSON message from server.
    response = await store_communicator.receive_json_from()

    assert_equal(message, response)

    await communicator.disconnect()

通信器函数 create_order 应该创建一个新的 channel_layer 组,客户和商店都应该添加到该组中。

async def create_order(self, event):
    order = await self._create_order(event.get('data'))
    order_id = f'{order.id}'

    # Add the customer to a group identified by order's key value.
    await self.channel_layer.group_add(
        group=order_id,
        channel=self.channel_name
    )

    # Confirm creation to customer.
    await self.send_json({
        'type': 'MESSAGE',
        'data': order_data
    })

理想情况下,我想在这里调用 group_add 并将频道设置为商店通信器的频道,但我不知道商店的频道名称。 有没有办法从用户的通信器实例中知道商店的频道名称?


我已经制定了一个解决方法,在该方法中,我向商店的通信器发送消息在上述 send_json 之前,如下所示:

    # HACK: Send notification to store
    await self.channel_layer.group_send(group=store_group, message={
        'type': 'notify.store',
        'data': order_data
    })

这会为商店调用第二个简单的通信器函数:

async def notify_store(self, event):
    data = event.get('data')
    await self.channel_layer.group_add(
        group=data['id'],
        channel=self.channel_name
    )

此解决方法不起作用。在发送第二个 echo.message 后,商店被添加到组中。 await self.channel_layer.group_send... 不会等到第二个通信器的 notify_store 执行完毕。有没有办法保证这种行为?


或者是否有一种完全不同的方法可以从一个用户的通信器向不同的用户添加到 channel_layer 组?

感谢您的宝贵时间。

【问题讨论】:

  • 我有点困惑,因为信息太多了。但据我所知,您想从另一个实例访问信息,例如,您通常通过调用 self.channel 访问该信息。 . 为什么不在某些数据库中注册实例信息?看看 django 频道存在的源代码。它非常简单易读,它展示了它是如何通过数据库支持实现的。所以你可以通过调用模型来访问代码中任何地方的信息跨度>

标签: python django python-3.x websocket django-channels


【解决方案1】:

我想你知道你需要做什么。您可以为商店创建一个组,唯一的工作就是获取订阅此订单组的消息。

但是,您没有考虑一些事情,例如如果商店不在线会怎样。然后您的客户的连接将永远阻塞。在 asyncio 中阻止这样的未来并不常见。如果你想这样做,你需要创建一个任务。通常,您不会等待另一个用户的会话发回响应。使其基于事件并尽快将控制权交还给事件循环。

看看做更多基于这样的事件:

  • 发送消息告诉商店订阅订单 身份证。
  • 在 JavaScript setTimeout 或具有 asyncio sleep 的 asyncio 任务中,它最终会超时并取消订阅所有组并断开连接并显示错误消息。
  • 让商店向其订阅的订单组发送消息。如果你 从商店获取消息取消超时并开始 交流。

您会发现这些东西很难测试,尤其是在您测试要接收的响应时。每条消息都像是一个新的请求。 Channels 确实需要一个更好的测试框架。因此,我的频道代码中几乎没有任何测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-07
    • 2016-12-28
    相关资源
    最近更新 更多