Python 在执行long函数之前,Flask不在呈现_模板中
我想创建一个等待页面,在执行一些长函数之前可以呈现该页面。当它完成时,它将重定向到success页面作为回报。这是一个简单的代码示例Python 在执行long函数之前,Flask不在呈现_模板中,python,flask,Python,Flask,我想创建一个等待页面,在执行一些长函数之前可以呈现该页面。当它完成时,它将重定向到success页面作为回报。这是一个简单的代码示例 @app.route("/process", methods=['GET', 'POST']) def process(): with app.app_context(): data = render_template('waiting.html') ### .. Do something long and have to wai
@app.route("/process", methods=['GET', 'POST'])
def process():
with app.app_context():
data = render_template('waiting.html')
### .. Do something long and have to wait .. ###
# e.g. sleep a few seconds
return redirect(url_for('success'))
发生的情况是,data=render\u template('waiting.html')
行似乎没有执行。我看到的是一段时间的空白屏幕(正如下面的处理功能)。并且,当它完成时,会按预期显示成功页面
这似乎是一项简单的任务,以前这里已经提出了许多问题。但这些解决方案对我不起作用。我的目标只是在执行任务之前显示模板。这样用户就可以看到他们的请求正在进行中
这是我试过的
- 我在上一个项目中考虑了芹菜。但是我发现它对于这个简单的工作来说太过合适了。所以我怀疑芹菜是一个体面的选择
谢谢 这里您缺少两件事:
render_template
将获取要呈现的模板的路径和要呈现模板的上下文,并返回字符串。因此,它不会对请求执行任何操作,它只会根据模板和上下文生成一个字符串(在您的代码示例中,它会将这个呈现的字符串存储在数据变量中)
对于2,您需要了解的是,当用户向您的/process
路由发出请求时,它将期望得到一个响应,并且只有一个响应
因此,您的路线需要决定响应什么:它是否是一个200OK
,包含一些内容(例如一些HTML)?或者一个301重定向
,它将指示用户的浏览器转到另一个页面?不能同时有两个响应,因为它违反了协议
为了获得您想要的体验,您必须指示用户的浏览器向您的服务器发出多个请求。有几种策略可以用于此,但最简单的可能是使用Ajax
这个想法是,您的初始路由将只呈现waiting.html
页面,但会有一些扭曲。在该页面中,您将添加一些JavaScript代码,这些代码向执行实际长时间运行任务的不同路径发出Ajax请求
现在有两条路线:
@app.route("/process", methods=['GET', 'POST'])
def process():
if request.method == 'GET':
return render_template('waiting.html')
if request.method == 'POST':
### .. Do something long and have to wait .. ###
# e.g. sleep a few seconds
return 'done'
(尽管这只是一种方法,但它们本质上是两条路线:GET/process
和POST/process
)
页面中的JavaScript将如下所示:
var request = new XMLHttpRequest();
request.open('POST', '/process');
request.onload = function() {
if (request.status === 200 && request.responseText === 'done') {
// long process finished successfully, redirect user
window.location = '/success';
} else {
// ops, we got an error from the server
alert('Something went wrong.');
}
};
request.onerror = function() {
// ops, we got an error trying to talk to the server
alert('Something went wrong.');
};
request.send();
(或如果您正在使用)
它将在后台向服务器发起另一个HTTP请求,启动长时间运行的作业,并将收到作为响应的文本done
。发生这种情况时,它会将用户重定向到/success
页面
现在,重要的是要记住,这是一个非常简单的问题,你需要记住一些事情:
这些Ajax请求中的每一个都会阻止与服务器的连接,如果您使用的是gunicorn之类的东西,那么服务器将是一个完整的工作程序。因此,如果您的处理时间过长,或者如果有很多并发用户访问此路由,那么您的服务器将非常过载
您需要正确处理错误。在我的示例中,我总是返回done
,并带有200ok
(这是默认状态代码),但如果处理过程中出现问题,您将返回并可能向用户显示某种错误消息
等待数据
不会返回。根据上面提到的方法,使用yield
尝试此解决方案
from flask import Response, stream_with_context
@app.route("/process", methods=['GET', 'POST'])
def process():
def generate_output():
with app.app_context():
yield render_template('waiting.html')
### .. Do something long and have to wait .. ###
# e.g. sleep a few seconds
# Later to find that we Can't yield redirect
# yield redirect(url_for('success'))
return Response(stream_with_context(generate_output()))
更新:很抱歉发现收益
只能用于将数据流传输到一个页面,而不能用于重定向。令人惊讶的是,我终于看到了等待页面。不过,我得到了断言错误:应用程序必须在最后写入字节。我不知道为什么。谢谢你的友好回复。不管怎样,知道这一点很好:)也许它可以与少量javascript配合使用yield
在需要缓冲响应时非常有用。这将不允许您做出两个回复。很抱歉回复太晚,谢谢您的明确解释。我确实误解了render_模板。现在我明白你关于HTTP响应的观点了。事实上,从那天起我就试过你的答案了。但我不得不修改我的代码在其他部分一点,使之工作。我会让你知道结果的!你的代码做了一个诡计!在我修改了请求和javascript之后。它就像一个符咒。我真的很感谢你的解释。再次感谢你!我想问另一个问题。如果我想将进度更新到模板,例如子任务2/5。你能建议我该怎么做吗?这很难在评论中回答,所以我建议你提出一个新问题。不过,你也有一些选择,我建议你在谷歌上搜索一些技术,比如WebSocket(可能有点过头了)、服务器发送事件(SSE)(不流行,所以不太流行)、轮询和长轮询(需要你在服务器中保持状态)。