Jac*_*022 5 python django ajax django-templates django-views
我正在构建一个将提供实时数据的 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
)
Run Code Online (Sandbox Code Playgroud)
模板
<h3> var: {{test}} </h3>
Run Code Online (Sandbox Code Playgroud)
我已经问过这个问题,但我有一些疑问:
有人告诉我使用 Ajax,这没问题,但是 Ajax 是否适合这种情况,我将每 x 秒加载一个包含实时更新数据的页面?
我还被告知使用 DRF(Django Rest Framework)。我一直在深入研究它,但我不清楚它是如何处理这个特殊情况的。
Mar*_*ndi 36
在下面,我给出了实现基于 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>
Run Code Online (Sandbox Code Playgroud)
在这里,我们打开了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>
Run Code Online (Sandbox Code Playgroud)
要配置 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),
]),
})
Run Code Online (Sandbox Code Playgroud)
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'],
})
Run Code Online (Sandbox Code Playgroud)
例如:
ticks = [
{'symbol': 'BTCUSDT', 'lastPrice': 1234, ...},
...
]
broadcast_ticks(ticks)
Run Code Online (Sandbox Code Playgroud)
在哪里:
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),
})
Run Code Online (Sandbox Code Playgroud)
我们需要将调用包含group_send()
在async_to_sync()
包装器中,因为 channel.layers 仅提供异步实现,并且我们从同步上下文调用它。Django Channels 文档中提供了更多详细信息。
笔记:
在某些情况下,轮询仍然是最合适的选择,简单而有效。
但是,在某些情况下,您可能会遇到一些限制:
使用 Websocket,您可以改为仅在有新数据可用时(并尽快)通过向客户端发送特定消息来通知客户端。