Django渠道-不断从服务器向客户端发送数据

时间:2018-08-07 11:37:26

标签: django websocket django-channels channels

请查看此example

如您所见,某种event不断被发送到客户端。我想在Django-Channels内部使用consumers.py来模仿。这是我所拥有的简化版本:

class ChatConsumer(AsyncConsumer):
    async def ws_connect(self, event):
        self.send = get_db_object()

        ....

        await self.send({
            "type": "websocket.accept"
        })

    # I need to CONSTANTLY receive & send data
    async def ws_receive(self, event):

        obj = ...# query DB and get the newest object

        json_obj = {
            'field_1': obj.field_1,
            'field_2': obj.field_2,
        }

        await self.send({
            "type": "websocket.send",
            "text": json.dumps(json_obj)
        })


    @database_sync_to_async
    def get_db_object(self, **kwargs):
        return Some_Model.objects.get(**kwargs)[0]

在这里,我希望我的Django后端能够不断运行:

  1. 查询数据库

  2. 从数据库接收obj

  3. event

  4. 将收到的obj发送到前端websocket

我该如何实现?重要的是我需要不断发送数据到客户端。

Internet上的大多数Django-Channels资源仅包含聊天应用程序,并不一定会不断向客户端发送数据。我找不到能完成此工作的任何工作代码。

请,关于Redis或渠道文档的更多建议……或者缺少一些缺少良好文档的随机第3方库...。推荐起来很容易,但是很难实现。例如,我发现有人推荐Snorky,但实际上它缺少有关如何实现它的文档。

但是,如果有一个专门从事此工作的网站,即使它不使用Django-Channels,我也可能会看一下。

谢谢!

2 个答案:

答案 0 :(得分:3)

我找到了解决方案。既然我注意到这篇文章的观看次数在相对较短的时间内就增长了很多,所以我相信很多人都在想同样的事情,所以我将其发布在这里。

consumers.py

import asyncio
from channels.consumer import AsyncConsumer

class ChatConsumer(AsyncConsumer):

    async def websocket_connect(self, event):
        print("connected", event)
        await self.send({
            "type": "websocket.accept"
        })

        while True:
            await asyncio.sleep(2)

            obj = # do_something (Ex: constantly query DB...)

            await self.send({
                'type': 'websocket.send',
                'text': # obj,
            })

    async def websocket_receive(self, event):
        print("receive", event)

    async def websocket_disconnect(self, event):
        print("disconnected", event)

jQuery

<script>

var loc = window.location;
var wsStart = 'ws://';
if (loc.protocol == 'https:') {
    wsStart = 'wss://'
}
var endpoint = wsStart + loc.host + loc.pathname;

var socket = new WebSocket(endpoint);

socket.onmessage = function(e){
    console.log("message", e);
};
socket.onopen = function(e){
    console.log("open", e);
};
socket.onerror = function(e){
    console.log("error", e)
};
socket.onclose = function(e){
    console.log("close", e)
};
</script>

您需要做的就是修改obj并将其发送。您可以根据需要扩展此功能。因此,现在我有兴趣在PostgreSQL中获取最新插入的行,并将该行注入到我的websocket中。我可以每2秒查询一次await asyncio.sleep(2)指定的数据库,然后将其注入到前端套接字中。

希望有帮助。

答案 1 :(得分:0)

使用channels == 1. *和Django == 1. *,例如,您可以使用线程模块:

# Some view.py
import threading
import time

class Publisher(threading.Thread):
    def __init__(self, reply_channel, frequency=0.5):
        super(Publisher, self).__init__()
        self._running = True
        self._reply_channel = reply_channel
        self._publish_interval = 1.0 / frequency

    def run(self):
        while self._running:
           self._reply_channel.send({'text': 'some data'})
           time.sleep(self._publish_interval)

    def stop(self):
        self._running = False

publishers = {}

def ws_connect(message):
    message.reply_channel.send({'accept': True})
    publisher = Publisher(reply_channel=message.reply_channel)
    publisher.start()
    publishers[message.reply_channel] = publisher

def ws_disconnect(message):
    publisher = publishers[message.reply_channel]
    publisher.stop()
    del publishers[message.reply_channel]