通过 Django Channels 和 Websockets 向客户端推送实时更新

Posted

技术标签:

【中文标题】通过 Django Channels 和 Websockets 向客户端推送实时更新【英文标题】:Push live updates to client through Django Channels & Websockets 【发布时间】:2018-02-27 11:53:58 【问题描述】:

我正在尝试制作一个向客户端显示实时更新数据的页面。该站点的其余部分是使用 Django 构建的,因此我正在尝试为此使用 Channels。

我显示的数据同时保存在 JSON 文件和 mysql 数据库中,以便在网站的其他部分进行进一步计算。理想情况下,我希望在收到最新数据时(即文件更新时)显示给客户端。

尽管据我所知,频道正是为此目的而构建的,但我在做这件事时遇到了麻烦。

我尝试从客户端发送多个请求,并在消费者中延迟和循环,但它要么(具有讽刺意味)仅在刷新时更新或立即更新。但是,这些方法都不是由文件或数据库中的更改触发的。

这是“有效”的代码,但并没有真正满足要求。 (另外,诚然,那里基本上什么都没有……)

# consumers.py
def ws_connect(message):
  message.reply_channel.send("accept": True)

def ws_receive(message):

  with open("data.json") as jsonfile:
    jsondata = json.load(jsonfile)

  res = json.dumps(jsondata)
  message.reply_channel.send( "text": res, )

#routing.py
from channels.routing import route
from .consumers import ws_receive, ws_connect


channel_routing = [
  route("websocket.receive", ws_receive, path=r"^/websockets/$"),
  route("websocket.connect", ws_connect, path=r"^/websockets/$"),
]

使用的JS:

<script>
var wsurl = "ws://" + "mywebsite.com" + "/websockets/";
socket = new WebSocket(wsurl);

socket.onopen = function() 
     socket.send("this is a request");
     console.log('sent');
  

socket.onmessage = function(message) 
    console.log(message.data);
    document.getElementById("livedata").innerhtml = message.data;

</script>

我很高兴有一个文档链接可以帮助我实现这样的目标,因为我整整一周都没有找到解决方案。

【问题讨论】:

【参考方案1】:

将用户添加到 ws_connect 上的 django 频道组

from channels.auth import channel_session_user_from_http
from channels import Group

@channel_session_user_from_http
def ws_connect(message, **kwargs):
    http_user = message.user
    if not http_user.is_anonymous:
        message.reply_channel.send('accept': True)
        Group('user-'+str(http_user.id)).add(message.reply_channel)`

通过

向用户发送任何新的更新数据
Group('user-1').send('text': 'hello user 1')
Group('user-2').send('text': 'hello user 2')

【讨论】:

这不只是将组添加到流量管理的方程式中吗?我的主要问题是找到一种在文件更新时从文件发送新数据的方法。 你必须使用 pynotify github.com/seb-m/pyinotify 来观察文件的变化。 @Roxerg:channels 并不是要为您观看文件。实现一个调用Group('user-1').send('text': 'file changes here') 的文件观察器,你就可以开始了。如果要发送 db 更改,请在 db change emit 上的 django 信号接收器中执行相同的调用。答案应该是公认的,因为在我看来没有什么可补充的。 @hoefling 那个文件观察器可以是一个单独的脚本吗?也就是说,我可以向consumers.py之外的组发送消息吗? @Roxerg:当然,唯一的要求是知道您要广播到的组名。从代码中的任何位置:from channels import Group; Group('user-1').send('text': 'what I have to say you').

以上是关于通过 Django Channels 和 Websockets 向客户端推送实时更新的主要内容,如果未能解决你的问题,请参考以下文章

通过 celery 向 django-channels 发送消息

如何通过 Django Channels 实现视频通话?

使用Django Channels 2上传文件

如何通过 Django Channels 将 cookie 添加到标头?

使用 Django Channels 2 上传文件

使用 django-channels/websocket 更新实时位置的有效方法