显示更新时从Flask视图流式传输的数据 [英] Display data streamed from a Flask view as it updates

查看:106
本文介绍了显示更新时从Flask视图流式传输的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个生成数据并实时流的视图。我不知道如何将这些数据发送到我可以在我的HTML模板中使用的变量。我目前的解决方案只是输出数据到一个空白页面到达,这是有效的,但我想包括在一个更大的页面格式。如何更新,格式化和显示数据流到页面?

  import flask 
import时间,数学

app = flask.Flask(__ name__)

@ app.route('/')
def index():
def inner():
#模拟一个很长的过程来观察
,我在范围内(500):
j = math.sqrt(i)
time.sleep(1)
#这个值应该插入HTML模板
yield str(i)+'< br /> \\\
'
return flask.Response(inner(),mimetype ='text / html')

app.run(debug = True)


解决方案

您可以在响应中传输数据,但不能按照描述的方式动态更新模板。模板在服务器端渲染一次,然后发送到客户端。您需要使用JavaScript来读取流式响应,并在客户端输出数据。

使用 XMLHttpRequest 向请求传输数据的端点发送请求。然后定期从流中读取,直到完成。



这个例子假设一个非常简单的消息格式:一行数据,后面跟一个换行符。只要有一种方法可以识别每条消息,您当然可以在解析时尽可能复杂。例如,你可以返回一个JSON对象,并在客户端解码它。

  from time import sleep 
from flask import Flask,render_template
from math import sqrt

app = Flask(__ name__)

@ app.route('/')
def index ):
#呈现将使用JavaScript读取流的模板(下面)
return render_template('index.html')

@ app.route('/ stream_sqrt ')
def stream():
def generate():
在范围内(500):
yield'{} \\\
'.format(sqrt(i ))
sleep(1)

return app.response_class(generate(),mimetype ='text / plain')

app.run()



< p>这是最新的输出:< span id =latest>< / span>< / p>
< p>这是所有的输出:< / 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;

函数handleNewData(){
//响应文本包括到目前为止的整个响应
//拆分消息,然后取消尚未处理的消息
//位置跟踪处理了多少个消息
//消息以换行结束,所以split将总是在最后显示一个额外的空消息
var messages = xhr.responseText.split( '\\\
');
messages.slice(position,-1).forEach(function(value){
latest.textContent = value; //更新最新值
//建立并追加一个新的item to a list to log all all
var item = document.createElement('li');
item.textContent = value;
output.appendChild(item);
} );
position = messages.length - 1;
}

var timer;
timer = setInterval(function(){
//检查新数据的响应
handleNewData();
//停止检查一次响应结束
if (xhr.readyState == XMLHttpRequest.DONE){
clearInterval(timer);
latest.textContent ='Done';
}
},1000);
< / script>


I have a view that generates data and streams it in real time. I can't figure out how to send this data to a variable that I can use in my HTML template. My current solution just outputs the data to a blank page as it arrives, which works, but I want to include it in a larger page with formatting. How do I update, format, and display the data as it is streamed 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)

解决方案

You can stream data in a response, but you can't dynamically update a template the way you describe. The template is rendered once on the server side, then sent to the client. You'll need to use JavaScript to read the streamed response and output the data on the client side.

Use XMLHttpRequest to make a request to the endpoint that will stream the data. Then periodically read from the stream until it is done.

This example assumes a very simple message format: a single line of data, followed by a newline. You can of course get as complicated in parsing as you like, as long as there's a way to identify each message. For example, you could 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>

这篇关于显示更新时从Flask视图流式传输的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆