我正在构建一个django应用程序,它将提供实时数据。我是Django的新手,现在我专注于如何实时更新数据,而不必重新加载整个页面。
一些澄清:实时数据应该定期更新,而不仅仅是通过用户输入。
查看
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>
我已经问过这个问题,但是我有一些疑问:
有人告诉我要使用Ajax,这没关系,但是Ajax是否适合这种情况,我将在每个页面上每x秒加载一次实时更新的数据?
我还被告知要使用DRF(Django Rest Framework)。我一直在仔细研究它,但是我不清楚它在这种特殊情况下如何工作。
答案 0 :(得分:1)
在下面,我在前面的评论中建议了一个清单,以实现基于Websocket和Django Channels的解决方案所需的操作清单。 最后给出了动机。
在客户端上,您需要执行以下javascript代码:
<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,然后在onmessage
回调中详细说明服务器发送的通知。
可能的改进:
<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>
要配置Django频道,请遵循以下说明:
https://channels.readthedocs.io/en/latest/installation.html
Channel Layers是Django Channels的可选组件,它提供了“组”抽象,我们将在以后使用。您可以按照此处给出的说明进行操作:
https://channels.readthedocs.io/en/latest/topics/channel_layers.html#
路由为Websocket(和其他协议)提供了已发布的终结点与关联的服务器端代码之间的映射,就像urlpattens在传统Django项目中为HTTP所做的一样
文件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),
]),
})
Consumer是一个类,为Websocket标准(以及可能的自定义)事件提供处理程序。从某种意义上说,它对Websocket的作用就像Django视图对HTTP的作用。
在我们的情况下:
文件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'],
})
例如:
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),
})
我们需要在group_send()
包装器中包含对async_to_sync()
的调用,因为channel.layers仅提供异步实现,而我们是从同步上下文中调用它。 Django Channels文档中提供了更多详细信息。
注意:
在某些情况下,轮询仍然是最合适的选择,因为它简单有效。
但是,在某些情况下,您可能会遇到一些限制:
使用Websocket,您可以改为(仅当有新数据可用时)通过向客户端发送特定消息来通知客户端。
答案 1 :(得分:0)
AJAX调用和REST API是您要寻找的组合。对于实时数据更新,最好的方法是定期轮询REST API。像这样:
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card card-default">
<div class="card-header">Goals</div>
<div class="card-body">
This is the goals example
</div>
</div>
</div>
</div>
</div>
</template>
现在将Django Rest Framework添加到您的项目中。他们有一个简单的教程here。创建一个API端点,该端点将以JSON形式返回数据,并在AJAX调用中使用该URL。
现在,您可能会感到困惑,因为在从function doPoll(){
$.post('<api_endpoint_here>', function(data) {
// Do operation to update the data here
setTimeout(doPoll, <how_much_delay>);
});
}
视图呈现页面时,您已将数据作为上下文传递到模板中。那将不再起作用。您必须添加一个脚本来更新元素的值,例如
home
其中document.getElementById("element_id").value = "New Value";
是您赋予元素的ID,element_id
是您从AJAX调用的响应中获取的数据。
我希望这会为您提供一个基本的背景。