本文介绍了实时动态更新Django模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个可提供实时数据的Django应用。我是Django的新手,现在我专注于如何实时更新数据,而不必重新加载整个页面。

I'm building a django app that will provide real time data. I'm fairly new to Django, and now i'm focusing on how to update my data in real time, without having to reload the whole page.

一些说明:实时数据应该定期更新,而不仅仅是通过用户输入。

Some clarification: the real time data should be update regularly, not only through a user input.

查看

def home(request):

    symbol = "BTCUSDT"
    tst = client.get_ticker(symbol=symbol)

    test = tst['lastPrice']

    context={"test":test}

    return render(request,
                  "main/home.html", context
                  )

模板

<h3> var: {{test}} </h3>

我已经问过这个问题,但是我有些疑问:

I already asked this question, but i'm having some doubts:

有人告诉我要使用Ajax,这没关系,但是Ajax是否适合这种情况,我将在该页面中加载每x秒实时更新的数据?

I've been told to use Ajax, and that's ok, but is Ajax good for this case, where i will have a page loaded with data updated in real time every x seconds?

我也被告知要使用DRF(Django Rest Framework)。我一直在仔细研究它,但是我不清楚它在这种特殊情况下如何工作。

I have also been told to use DRF (Django Rest Framework). I've been digging through it a lot, but what it's not clear to me is how does it work with this particular case.

推荐答案

在下面,我在前面的评论中建议了一个清单,以实现基于Websocket和Django Channels的解决方案所需的操作清单。
最后给出了动机。

Here below, I'm giving a checklist of the actions needed to implement a solution based on Websocket and Django Channels, as suggested in a previous comment.The motivation for this are given at the end.

在客户端上,您需要执行以下javascript代码:

On the client, you need to execute the follwing javascript code:

<script language="javascript">
    var ws_url = 'ws://' + window.location.host + '/ws/ticks/';
    var ticksSocket = new WebSocket(ws_url);

    ticksSocket.onmessage = function(event) {
        var data = JSON.parse(event.data);
        console.log('data', data);
        // do whatever required with received data ...
    };
</script>

在这里,我们打开Websocket,然后在<$ c中详细说明服务器发送的通知$ c> onmessage 回调。

Here, we open the Websocket, and later elaborate the notifications sent by the server in the onmessage callback.

可能的改进:


  • 支持SSL连接

  • 使用ReconnectingWebSocket:WebSocket API上的一个小型包装,可自动重新连接

    <script language="javascript">
        var prefix = (window.location.protocol == 'https:') ? 'wss://' : 'ws://';
        var ws_url = prefix + window.location.host + '/ws/ticks/';
        var ticksSocket = new ReconnectingWebSocket(ws_url);
        ...
    </script>



2)安装和配置Django通道和通道层



要配置Django频道,请遵循以下说明:

2) Install and configure Django Channels and Channel Layers

To configure Django Channels, follow these instructions:

渠道层是Django Channels提供了组抽象,我们将在以后使用;您可以按照此处给出的说明进行操作:

Channel Layers is an optional component of Django Channels which provides a "group" abstraction which we'll use later; you can follow the instructions given here:

路由为Websocket(和其他协议)提供了已发布的端点与关联的服务器端代码之间的映射,就像urlpattens在传统Django项目中为HTTP所做的一样

Routing provides for Websocket (and other protocols) a mapping between the published endpoints and the associated server-side code, much as urlpattens does for HTTP in a traditional Django project

文件 routing.py

from django.urls import path
from channels.routing import ProtocolTypeRouter, URLRouter
from . import consumers

application = ProtocolTypeRouter({
    "websocket": URLRouter([
        path("ws/ticks/", consumers.TicksSyncConsumer),
    ]),
})



4)写出消费者



Consumer是一个类,为Websocket标准(可能还有自定义)事件提供处理程序。从某种意义上说,它对Websocket的作用类似于Django视图对HTTP的作用。

4) Write the consumer

The Consumer is a class which provides handlers for Websocket standard (and, possibly, custom) events. In a sense, it does for Websocket what a Django view does for HTTP.

在我们的例子中:


  • websocket_connect():我们接受连接并向滴答组注册传入的客户端

  • websocket_disconnect():通过从组中删除che客户端进行清理
  • new_ticks():我们的自定义处理程序,将接收到的报价广播到它的Websocket客户端

  • 我假设TICKS_GROUP_NAME是项目设置中定义的常量字符串值

  • websocket_connect(): we accept the connections and register incoming clients to the "ticks" group
  • websocket_disconnect(): cleanup by removing che client from the group
  • new_ticks(): our custom handler which broadcasts the received ticks to it's Websocket client
  • I assume TICKS_GROUP_NAME is a constant string value defined in project's settings

文件 consumers.py

from django.conf import settings
from asgiref.sync import async_to_sync
from channels.consumer import SyncConsumer

class TicksSyncConsumer(SyncConsumer):

    def websocket_connect(self, event):
        self.send({
            'type': 'websocket.accept'
        })

        # Join ticks group
        async_to_sync(self.channel_layer.group_add)(
            settings.TICKS_GROUP_NAME,
            self.channel_name
        )

    def websocket_disconnect(self, event):
        # Leave ticks group
        async_to_sync(self.channel_layer.group_discard)(
            settings.TICKS_GROUP_NAME,
            self.channel_name
        )

    def new_ticks(self, event):
        self.send({
            'type': 'websocket.send',
            'text': event['content'],
        })



5)最后:广播新的滴答声



例如:

5) And finally: broadcast the new ticks

For example:

ticks = [
    {'symbol': 'BTCUSDT', 'lastPrice': 1234, ...},
    ...
]
broadcast_ticks(ticks)

其中:

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

def broadcast_ticks(ticks):
    channel_layer = channels.layers.get_channel_layer()
    async_to_sync(channel_layer.group_send)(
        settings.TICKS_GROUP_NAME, {
            "type": 'new_ticks',
            "content": json.dumps(ticks),
        })

我们需要将调用包含在 async_to_sync()包装器中的group_send(),因为channel.layers仅提供异步实现,我们从同步上下文中调用它。有关更多详细信息,请参见Django Channels文档。

We need to enclose the call to group_send() in the async_to_sync() wrapper, as channel.layers provides only the async implementation, and we're calling it from a sync context. Much more details on this are given in the Django Channels documentation.

注意:


  • 确保 type属性与使用者处理程序的名称匹配(即: new_ticks);

  • 每个客户都有自己的消费者;因此,当我们在消费者的处理程序中编写self.send()时,这意味着:将数据发送到单个客户端

  • 在这里,我们将数据发送到组抽象中,然后将Channel层依次将其提供给每个注册的消费者

投票

但是,在某些情况下,仍然是最合适的选择。

However, on some occasions you might suffer a few limitations:


  • 即使没有可用的新数据,您也会继续查询服务器

  • 您会引入一些延迟(最坏的情况是整个周期的投票)。代价是:更少的延迟=更多的流量。

使用Websocket,您可以(仅当(并尽快)有新数据时)通过向客户端发送特定的通知来通知客户端信息。

With Websocket, you can instead notify the clients only when (and as soon as) new data are available, by sending them a specific message.

这篇关于实时动态更新Django模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 19:40