web-dev-qa-db-ja.com

Flaskを使用してページの強制更新を実装する最良の方法は何ですか?

背景
外部プロセスからリアルタイムで更新されるフィールドが多数あります。 Flaskホストされているページを定期的に更新して、接続されているユーザーに変更を表示したいと思います。理想的には、ページ全体が更新されないことです。これは同様のシステムの苦情でしたが、ページ上のフィールド。

現在の方向
私の現在の考えは、JavaScriptを使用してこれを処理することですが、Flaskを使用した場合でもそれが可能かどうかはわかりません。

Flaskまたはサードパーティモジュールでこれを実現する方法はありますか?

追加情報
データは、さまざまなソケットとシリアルポートを使用して更新されます。各インターフェイスは独自のスレッドで実行され、共有メモリを更新します。 Flask/Webインターフェイスには、他のスレッドで更新できる共有メモリへの読み取り専用書き込みがあることに注意してください。

合計クライアントプールは20人を超えてはなりません。これはテストシステムへのWebインターフェイスであり、通常、一度に接続できるのは1〜5人だけです。

22
Adam Lewis

ページ全体が更新されないようにするには、AJAXと呼ばれるものを使用します。これは簡単にできるようです フラスコに実装

定期的に発生させたいので、javascriptの timer 関数からAJAX関数を呼び出す必要があります。

これは、flaskページからのJavaScriptをタイマー呼び出し内に置くだけであることを意味します。

Javascriptは次のようになります。

setInterval(                               //Periodically 
  function()
  {
     $.getJSON(                            //Get some values from the server
        $SCRIPT_ROOT + '/get_values',      // At this URL
        {},                                // With no extra parameters
        function(data)                     // And when you get a response
        {
          $("#result").text(data.result);  // Write the results into the 
                                           // #result element
        });
  },
  500);                                    // And do it every 500ms
17

おそらくこれを行う最も簡単な方法は、質問ですでに提案しているようにjavascriptを使用することだと思います。この場合、Flaskは、ブラウザによって実行されるJavaScriptコードを含むHTMLドキュメントを配信するだけなので、Flaskに問題が発生する理由がわかりません。 このページ 、タイマーを使用するなど、さまざまな組み合わせを使用した例をいくつか見つけました(これはあなたが探しているもののようです)。

4
jcollado

いいえ。少なくとも、Flaskの側には、他のソリューションよりもこれを簡単にするものはありません。SOには、 実装)に関する適切な資料があります。 Pythonのcometサーバー

前述のように、JavaScriptを使用してサーバーをポーリングして新しいデータを探すことができます。多くのユーザーがいる場合でも、これはサーバーが管理するのが難しい場合があります。同時接続を開くTCP接続はかなりコストがかかります。また、新しいデータがサーバーに到達したときではなく、1秒ごとに更新されるため、UIが少しぎくしゃくしているように見える場合があります。

そのことを念頭に置いて、Flaskは、応答関数を個々のURLに簡単に添付できるため、この2番目の選択肢に最適です。主な注意点は、I/Oを大幅にブロックする関数を使用する必要があることです。 。実行時間の長い関数は、アプリケーション全体を占有します。

2つの温度ゲージがあり、jQueryを使用しているとします。

@app.route('/gauge/<int:gauge_id>')
def gauge_temp(gauge_id):
    temp = temp_from_db(gauge_id) #implement this yourself
    return dict(temp=temp, gauge_id=gauge_id)

JavaScriptファイルでは、現在の温度で1分ごとにDOM要素を更新する関数を使用できます。このコードは、実際の実装に組み込むことができる何かのアイデアを提供するはずです。

function updateTemp(gauge_id, selector) {
  $.getJSON('/gauge/' + gauge_id, function(data){
    $(selector).text = response.temp;
  })
}

setInterval('updateTemp(1, "#gauge-1")', 1000 * 60);
setInterval('updateTemp(2, "#gauge-2")', 1000 * 60);
2
Tim McNamara

これを実現する1つの方法は、Flask WebSocketsを使用してflask-socketioを使用することです。例のバックグラウンドプロセスにはAPSchedulerを使用しますが、バックグラウンドプロセスであれば何でもかまいません。これにより、4秒ごとにWebページの価格が更新されます。

from flask import Flask, render_template
from apscheduler.schedulers.background import BackgroundScheduler
from flask_socketio import SocketIO, emit

app = Flask(__name__)
socketio = SocketIO(app)

#defines the job
def job():
    new_price = get_new_price();
    #job emits on websocket
    socketio.emit('price update',new_price, broadcast=True)

#schedule job
scheduler = BackgroundScheduler()
running_job = scheduler.add_job(job, 'interval', seconds=4, max_instances=1)
scheduler.start()

@app.route('/')
def index():
    return render_template('index.html')

if __name__ == '__main__':
    socketio.run(app, Host='0.0.0.0')

次に、index.htmlテンプレートは次のとおりです。

<!DOCTYPE HTML>
<html>
<head>
    <title>WebSockets Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
    <script type="text/javascript" charset="utf-8">
       $(document).ready(function(){

           var socket = io.connect('http://' + document.domain + ':' + location.port);

           socket.on('connect', function() {
               socket.emit('am up', {data: 'I\'m connected!'});
           });
           //listens to 'price update' message on socket
           socket.on('price update', function(msg) {
               $('#price_info').text(msg)
           });

       });
   </script>
</head>
<body>
  <div id="price_info"></div>
</body>
</html>
0
Vladtn