web-dev-qa-db-de.com

Wie kann eine erzwungene Seitenaktualisierung mit Flask am besten implementiert werden?

Hintergrund
Ich habe eine große Anzahl von Feldern, die in Echtzeit von einem externen Prozess aktualisiert werden. Ich möchte die von Flask gehosteten Seiten regelmäßig aktualisieren, um verbundenen Benutzern etwaige Änderungen anzuzeigen. Im Idealfall würde die gesamte Seite nicht aktualisiert. Dies war eine Beschwerde eines ähnlichen Systems, sondern es wurden lediglich einige Felder auf der Seite aktualisiert.

Aktuelle Richtung
Ich denke derzeit daran, möglicherweise ein JavaScript zu verwenden, um dies zu handhaben, aber ich bin mir nicht sicher, ob dies überhaupt möglich ist, wenn ich Flask verwende.

Gibt es eine Möglichkeit mit Flask oder 3rd-Party-Modul, um dies zu erreichen?

Zusätzliche Information
Die Daten werden über verschiedene Sockets und serielle Ports aktualisiert. Jede Schnittstelle wird in einem eigenen Thread ausgeführt und aktualisiert den gemeinsamen Speicher. Beachten Sie, dass die Flask/Web-Oberfläche nur Lesezugriff auf den gemeinsam genutzten Speicher hat, der von den anderen Threads aktualisiert werden kann.

Der gesamte Kundenpool sollte niemals 20 Personen überschreiten. Dies ist eine Webschnittstelle zu einem Testsystem, mit der im Allgemeinen jeweils nur 1-5 Personen verbunden sind.

21
Adam Lewis

Um zu vermeiden, dass die gesamte Seite aktualisiert wird, verwenden Sie das sogenannte AJAX. Es sieht so aus, als sei dies einfach in Kolben umzusetzen .

Da Sie möchten, dass es regelmäßig geschieht, müssen Sie Ihre AJAX - Funktionen von einer timer - Funktion in Javascript aufrufen.

Dies bedeutet, dass Sie das Javascript aus der Flaschenseite in einen Timer-Aufruf einfügen.

Hier sehen Sie ungefähr, wie das Javascript aussehen würde:

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

Ich denke, wahrscheinlich ist dies der einfachste Weg, Javascript zu verwenden, wie Sie es bereits in Ihrer Frage vorgeschlagen haben. In diesem Fall würde Flask lediglich ein HTML-Dokument liefern, das JavaScript-Code enthält, der vom Browser ausgeführt werden soll. Ich kann also nicht verstehen, warum Flask dadurch möglicherweise Probleme verursacht. In diese Seite habe ich einige Beispiele gefunden, bei denen verschiedene Kombinationen verwendet wurden, z. B. die Verwendung eines Timers (der scheinbar das ist, was Sie suchen).

3
jcollado

Nun, zumindest gibt es nichts in Flask, das dies einfacher machen würde als andere Lösungen. SO enthält anständiges Material zur Implementierung von Comet-Servern in Python .

Wie Sie bereits erwähnt haben, können Sie JavaScript verwenden, um den Server nach neuen Daten abzufragen. Dies kann für Ihren Server jedoch schwierig sein, wenn Sie viele Benutzer haben. Das Öffnen von gleichzeitigen TCP-Verbindungen ist ziemlich teuer. Dies bedeutet auch, dass Ihre Benutzeroberfläche möglicherweise etwas ruckartig erscheint, da die Dinge etwa jede Sekunde aktualisiert werden und nicht, wenn neue Daten auf den Server gelangen.

Flask eignet sich daher hervorragend für diese zweite Wahl, da es so einfach ist, Antwortfunktionen an einzelne URLs anzuhängen. Die Hauptsache, die Sie beachten sollten, sind Funktionen, die die E/A stark blockieren. Langfristige Funktionen erfassen die gesamte Anwendung.

Nehmen wir an, Sie haben zwei Temperaturmessgeräte und verwenden 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)

In einer JavaScript-Datei könnten Sie über eine Funktion verfügen, die ein DOM-Element jede Minute mit der aktuellen Temperatur aktualisiert. Dieser Code sollte Ihnen einen Eindruck von etwas vermitteln, das Sie in eine tatsächliche Implementierung integrieren können:

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

Eine Möglichkeit, dies zu erreichen, ist in Flask durch WebSockets mit flask-socketio . Ich benutze APScheduler für den Hintergrundprozess im Beispiel, aber jeder Hintergrundprozess reicht aus. Dies aktualisiert alle 4 Sekunden einen Preis auf der Webseite:

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 __== '__main__':
    socketio.run(app, Host='0.0.0.0')

Dann ist das index.html template:

<!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