Flask:持续显示Flash消息

时间:2019-02-14 11:31:02

标签: python flask subprocess

我开发了一个flask应用程序,该应用程序运行数学优化脚本(PuLP + Python),用于用户提供的数据输入。由于计算需要花费一段时间,因此我想在我的网页上不断显示优化程序的打印语句(无需刷新)。

基于this solution,我设法通过subprocess脚本运行了.py。在此脚本中,print()语句应做的事,但是我只能在命令行中看到输出。通过使用flash(),我设法显示了输出,但是仅在计算完成并重新加载页面后才呈现输出。我尝试在我的HTML中实时输出print()语句。有没有办法做到这一点?

谢谢!

摘录自routes.py

@app.route('/optimize', methods=['GET', 'POST'])
    def solve():
    path = os.path.join(app.root_path, 'optimization', 'assets')
    file = "test.py"
    execute(file, path)

return redirect(url_for('home'))

execute(file,path)函数:

import os
import subprocess as sub

def execute(command, directory):

    # change directory to execute the command
    os.chdir(directory)

    proc = sub.Popen(['python','-u', command], stdout=sub.PIPE, universal_newlines=True) # Python 2: bufsize=1

    for stdout_line in proc.stdout:
        print(stdout_line.rstrip() + '\n')
        flash(stdout_line.rstrip(), 'python_print')
    proc.stdout.close()
    return_code = proc.wait()
    if return_code:
        raise sub.CalledProcessError(return_code, command)

最后是我的HTML,它是在home路线中呈现的:

{% with prints = get_flashed_messages(category_filter=["python_print"]) %}
{% if prints %}
<div class="content-section">
    <h3>Solver Status</h3>
    <ul>
        {%- for message in prints %}
        <li>{{ message }}</li>
        {% endfor -%}
    </ul>
</div>
{% endif %}
{% endwith %}

2 个答案:

答案 0 :(得分:0)

据我所知,这应该是消息闪烁的工作方式,即它将一次显示特定端点的所有消息。

我不确定确切的实现方式,因为我没有查看flash()get_flash_messages()的源代码,但这是我对后台可能发生的事情的理解,每条消息闪烁在您的python代码中使用flash函数,它会附加到一个可迭代对象上,当您调用get_flashed_messages()时,它将返回该可迭代对象,您可以循环获取消息。

尽管您的execute()函数在过程完成之前向其添加了可迭代的消息,但是请注意,execute函数正在视图solve和实际的{{1 }}仅在redirect函数完成执行之后才能发生,那时模板execute将具有所有已刷新的消息进行迭代。

希望如此。

答案 1 :(得分:0)

根据提供的建议,我更改了方法并开始运行。代替使用subprocess,将求解器作为模块导入。我正在使用python .txt模块生成一个logging,而不是试图捕获print语句。该文件使用flask response + yield不断进行流传输,并通过AJAX进行解析。 jQuery中的setInterval(此处为1Hz)调用了getter,并将其添加到我的HTML中。我将在下面发布一些摘要,以供处理相同问题的任何人使用。

感谢您的支持!

烧瓶优化路径:

import supplierAllocation.optimization.optimizer as optimizer

@app.route('/optimize')
def optimize():

    if session.get('input_file') is not None:

        # Get input_file
        input_file = session.get('input_file')

        # Path to logfile
        log_file = os.path.join(
            app.config['LOG_FOLDER'], session.get('log_file'))

        # Assign random unique hex file name from session to output file
        out_file_fn = session.get('session_ID') + '.xlsx'
        output_file = os.path.join(app.config['DOWNLOAD_FOLDER'], out_file_fn)

        # Search for outdated output; if present: delete
        if session.get('output_file') is None:
            session['output_file'] = out_file_fn
        else:
            session_output = os.path.join(
                app.config['DOWNLOAD_FOLDER'], session.get('output_file'))
            silent_remove(session_output)

        # Pass input and output parameter to solver
        optimizer.launch_solver(input_file, output_file, log_file)

    else:
        flash("Please upload your data before launching the solver!", 'warning')

    return redirect(url_for('home'))

烧瓶流路由:

@app.route('/streamLog')
def stream_logfile():
    if session.get('log_file') is None:
        return Response(status=204)
    else:
        session_log = os.path.join(
            app.config['LOG_FOLDER'], session.get('log_file'))

        def stream():
            with open(session_log, "rb") as file:
                yield file.read()

        return Response(stream(), mimetype='text/plain')

点击按钮即可调用AJAX请求:

// Print solver output with 1Hz
var session_log = setInterval(get_Log, 1000);

jQuery中的AJAX请求:

// AJAX Request to download solutions
function get_Log() {
  console.log('Sending AJAX request...');
  $.ajax({
    url: "streamLog",
    dataType: "text",
    success: function(result) {
      $("#code-wrapper").html(result);
    },
    error: function() {
      console.log("ERROR! Logfile could not be retrieved.");
    }
  });
}