我开发了一个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 %}
答案 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.");
}
});
}