Display data passed from the flag when updating

I have a view that generates data and transmits them in real time. I cannot figure out how to send this data to a variable that I can use in my HTML template. My current solution simply displays data on a blank page as it arrives, but I want to include it on a larger page with formatting. How to update, format and display data as it is transferred to the page?

import flask import time, math app = flask.Flask(__name__) @app.route('/') def index(): def inner(): # simulate a long process to watch for i in range(500): j = math.sqrt(i) time.sleep(1) # this value should be inserted into an HTML template yield str(i) + '<br/>\n' return flask.Response(inner(), mimetype='text/html') app.run(debug=True) 
+7
javascript python flask stream
source share
1 answer

You can send data in response, but you cannot dynamically update the template as you describe. The template is created once on the server side, and then sent to the client. You will need to use JavaScript to read the streaming response and output the data on the client side.

Use XMLHttpRequest to query the endpoint that will transmit the data. Then periodically read the thread until it is executed.

This example uses a very simple message format: one line of data followed by a new line. Of course, you can get as complicated in parsing as you want if there is a way to identify each message. For example, you can return a JSON object and decode it on the client.

 from time import sleep from flask import Flask, render_template from math import sqrt app = Flask(__name__) @app.route('/') def index(): # render the template (below) that will use JavaScript to read the stream return render_template('index.html') @app.route('/stream_sqrt') def stream(): def generate(): for i in range(500): yield '{}\n'.format(sqrt(i)) sleep(1) return app.response_class(generate(), mimetype='text/plain') app.run() 
 <p>This is the latest output: <span id="latest"></span></p> <p>This is all the output:</p> <ul id="output"></ul> <script> var latest = document.getElementById('latest'); var output = document.getElementById('output'); var xhr = new XMLHttpRequest(); xhr.open('GET', '{{ url_for('stream') }}'); xhr.send(); var position = 0; function handleNewData() { // the response text include the entire response so far // split the messages, then take the messages that haven't been handled yet // position tracks how many messages have been handled // messages end with a newline, so split will always show one extra empty message at the end var messages = xhr.responseText.split('\n'); messages.slice(position, -1).forEach(function(value) { latest.textContent = value; // update the latest value in place // build and append a new item to a list to log all output var item = document.createElement('li'); item.textContent = value; output.appendChild(item); }); position = messages.length - 1; } var timer; timer = setInterval(function() { // check the response for new data handleNewData(); // stop checking once the response has ended if (xhr.readyState == XMLHttpRequest.DONE) { clearInterval(timer); latest.textContent = 'Done'; } }, 1000); </script> 
+10
source share

All Articles