web-dev-qa-db-fra.com

Quel est le meilleur moyen d'implémenter un rafraîchissement de page forcé à l'aide de Flask?

Contexte
J'ai un grand nombre de champs qui seront mis à jour en temps réel à partir d'un processus externe. Je souhaite mettre à jour les pages hébergées de Flask régulièrement pour montrer aux utilisateurs connectés tout changement. Idéalement, la page entière ne serait pas actualisée, il s’agissait d’une réclamation émanant d’un système similaire, mais plutôt d’une simple mise à jour d’un certain nombre de champs de la page.

Direction actuelle
Mon idée actuelle est d’utiliser éventuellement un JavaScript pour gérer cela, mais je ne suis pas sûr que ce soit même possible avec Flask.

Y at-il un moyen avec Flask, ou un module tiers, d'accomplir cela?

Information additionnelle
Les données seront mises à jour à l'aide de divers sockets et ports série. Chaque interface fonctionnera dans son propre thread et mettra à jour la mémoire partagée. Notez que l'interface Flask/Web contient des écritures en lecture seule dans la mémoire partagée pouvant être mises à jour par les autres threads.

Le nombre total de clients ne devrait jamais dépasser 20 personnes. Il s’agit d’une interface Web menant à un système de test. En général, seulement 1 à 5 personnes y sont connectées à un moment donné.

21
Adam Lewis

Pour éviter d'actualiser toute la page, vous souhaitez utiliser ce que l'on appelle AJAX. Il semble que cela soit facile à mettre en œuvre dans un flacon .

Puisque vous voulez que cela se produise périodiquement, vous devez appeler vos fonctions AJAX à partir de timer fonction en javascript.

Cela signifie que vous venez de placer le javascript de la page de la fiole dans un appel programmé.

Voici à peu près à quoi ressemblerait le 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
Michael Anderson

Je pense que le moyen le plus simple de le faire est d’utiliser javascript comme vous le suggérez déjà dans votre question. Dans ce cas, Flask fournirait simplement un document HTML contenant du code javascript à exécuter par le navigateur. Par conséquent, je ne vois pas pourquoi cela pourrait poser problème à Flask. Dans cette page , j'ai trouvé quelques exemples utilisant différentes combinaisons, telles que l'utilisation d'une minuterie (ce qui semble être ce que vous recherchez).

3
jcollado

Non. Au moins rien dans Flask ne rendrait cela plus facile que d’autres solutions. SO a un contenu décent sur implémentant des serveurs comet en Python .

Comme vous l'avez mentionné, vous pouvez utiliser JavaScript pour interroger le serveur à la recherche de nouvelles données. Cela peut être difficile à gérer pour votre serveur si vous avez plusieurs utilisateurs. Ouvrir des connexions simultanées TCP est assez coûteux. Cela signifie également que votre interface utilisateur peut sembler légèrement saccadée, car les choses seront mises à jour toutes les secondes environ, plutôt que lorsque de nouvelles données arrivent sur le serveur.

Dans cet esprit, Flask est excellent pour ce second choix car il est si facile d’attacher des fonctions de réponse à des URL individuelles. La principale chose à noter est que vous devriez utiliser des fonctions qui bloquent fortement les E/S. Les fonctions de longue durée vont saisir l'ensemble de l'application.

Disons que vous avez deux indicateurs de température et que vous utilisez 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)

Dans un fichier JavaScript, vous pouvez avoir une fonction qui met à jour un élément DOM toutes les minutes avec la température actuelle. Ce code devrait vous donner une idée de quelque chose que vous pouvez intégrer dans une implémentation réelle:

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

Une façon d'y parvenir est d'utiliser Flask via WebSockets à l'aide de flask-socketio . J'utilise APScheduler pour le processus d'arrière-plan dans l'exemple, mais tout processus d'arrière-plan fera l'affaire. cela met à jour un prix sur la page Web toutes les 4 secondes:

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')

Alors le index.html template est:

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