簡體   English   中英

實時動態更新Django模板

[英]Dynamic updates in real time to a django template

我正在構建一個將提供實時數據的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)。 我一直在仔細研究它,但是對我來說尚不清楚的是它在這種情況下如何工作。

在下面的內容中,我提供了一個清單,該清單列出了實現Websocket和Django Channels解決方案所需的操作,如上一條注釋中所建議。 最后給出了動機。

1)連接到Websocket並准備接收消息

在客戶端上,您需要執行以下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回調中詳細說明服務器發送的通知。

可能的改進:

  • 支持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頻道,請按照以下說明進行操作:

https://channels.readthedocs.io/en/latest/installation.html

Channel Layers是Django Channels的可選組件,它提供了“組”抽象,我們將在以后使用; 您可以按照此處給出的說明進行操作:

https://channels.readthedocs.io/zh-CN/latest/topics/channel_layers.html#

3)發布Websocket端點

路由為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),
    ]),
})

4)寫出消費者

消費者是一個類,它為Websocket標准(以及可能的自定義)事件提供處理程序。 從某種意義上說,它對Websocket的作用類似於Django視圖對HTTP的作用。

在我們的情況下:

  • websocket_connect():我們接受連接並將進入的客戶端注冊到“ ticks”組
  • websocket_disconnect():通過從組中刪除客戶端來進行清理
  • new_ticks():我們的自定義處理程序,將接收到的滴答廣播到其Websocket客戶端
  • 我假設TICKS_GROUP_NAME是項目設置中定義的常量字符串值

文件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)最后:廣播新的滴答聲

例如:

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文檔中提供了更多詳細信息。

筆記:

  • 確保“類型”屬性與使用者處理程序的名稱匹配(即:“ new_ticks”); 這是必需的
  • 每個客戶都有自己的消費者; 因此,當我們在使用者的處理程序中編寫self.send()時,這意味着:將數據發送到單個客戶端
  • 在這里,我們將數據發送到“組”抽象,然后通道層將依次將其傳遞給每個注冊的使用者

動機

在某些情況下,輪詢仍然是簡單有效的最合適的選擇。

但是,在某些情況下,您可能會遇到一些限制:

  • 即使沒有新數據可用,您仍會繼續查詢服務器
  • 您會引入一些延遲(最壞的情況是整個輪詢周期)。 代價是:更少的延遲=更多的流量。

使用Websocket,您可以改為(僅當有新數據可用時)通過向客戶端發送特定消息來通知客戶端。

AJAX調用和REST API是您要尋找的組合。 對於實時數據更新,最好的方法是定期輪詢REST API。 就像是:

function doPoll(){
    $.post('<api_endpoint_here>', function(data) {
        // Do operation to update the data here
        setTimeout(doPoll, <how_much_delay>);
    });
}

現在,將Django Rest Framework添加到您的項目中。 他們在這里有一個簡單的教程。 創建一個API端點,該端點將以JSON形式返回數據,並在AJAX調用中使用該URL。

現在您可能會感到困惑,因為您是在從home視圖渲染頁面時將數據作為上下文傳遞到模板中的。 那將不再起作用。 您必須添加腳本來更新元素的值,例如

document.getElementById("element_id").value = "New Value";

其中element_id是您賦予該元素的ID, "New Value"是您從AJAX調用的響應中獲取的數據。

我希望這會為您提供一個基本的背景。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM