How do I change the rendered template in Flask when a thread completes?
An easy way is making cyclic Ajax requests to a thread_status endpoint that gives you information about the currently running task.
import timefrom flask import Flask, jsonifyfrom flask import render_templatefrom threading import Threadapp = Flask(__name__)th = Thread()finished = False@app.route("/")def init(): return render_template('index.html')@app.route("/", methods=['POST'])def load(): global th global finished finished = False th = Thread(target=something, args=()) th.start() return render_template('loading.html')def something(): """ The worker function """ global finished time.sleep(5) finished = True@app.route('/result')def result(): """ Just give back the result of your heavy work """ return 'Done'@app.route('/status')def thread_status(): """ Return the status of the worker thread """ return jsonify(dict(status=('finished' if finished else 'running')))if __name__ == "__main__": app.run(debug=True)
So in your loading.html just insert a cyclic Ajax get()
request:
<html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <script> $(document).ready(function() { var refresh_id = setInterval(function() { $.get( "{{ url_for('thread_status') }}", function(data) { console.log(data); if (data.status == 'finished') { window.location.replace("{{ url_for('result') }}"); } } )} , 1000); }); </script> </head> <body> <p>Loading...</p> </body></html>
You can even append this by a progress counter if you like. But you need to take care that you prevent the thread from being run multiple times.