在执行长函数之前,Flask 不是 render_template

Fon*_*Lew 2 python flask

我想创建一个等待页面,我可以在执行一些长函数之前呈现这个页面。当它完成时,它将重定向到成功页面作为回报。这是一个简单的代码示例

@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'))
Run Code Online (Sandbox Code Playgroud)

发生的事情是该行data = render_template('waiting.html')似乎没有执行。我看到的是一段时间的空白屏幕(因为它是下面的处理功能)。并且,当它完成时,它会按预期显示成功页面。

以前在这里问过很多问题,这似乎是一项简单的任务。但是这些解决方案对我不起作用。我的目标只是在执行任务之前显示模板。这样用户就会看到他们的请求正在进行中。

这是我尝试过的。

如果我误解了 Flask 的概念,请告诉我。谢谢!

Lui*_*qui 5

您在这里缺少两件事:

  1. render_template实际上是做什么的
  2. HTTP 流如何工作

对于 1,答案很简单。render_template将获取您想要呈现的模板的路径以及您想要呈现模板的上下文并返回一个字符串。所以它不会对请求做任何事情,它只会根据模板和上下文生成一个字符串(在你的代码示例中,它会将这个呈现的字符串存储在data变量中)。

对于 2,您需要了解的是,当用户向您的/process路由发出请求时,它会期待一个响应,并且只有一个响应。

所以你的路由需要决定响应什么:它会200 OK包含一些内容(例如一些 HTML)吗?或301 Redirect将指示用户的浏览器转到另一个页面?您不能同时拥有这两个响应,因为它违反了协议。

为了获得您想要的体验,您必须指示用户的浏览器向您的服务器发出多个请求。为此,您可以使用几种策略,但最简单的一种可能是使用 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'
Run Code Online (Sandbox Code Playgroud)

(尽管它只是一种方法,但它们本质上是两条路线:GET /processPOST /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();
Run Code Online (Sandbox Code Playgroud)

(或者如果您使用的是jQuery

这将做的是它将在后台向您的服务器发起另一个 HTTP 请求,该请求将启动该长期运行的作业,并将接收文本作为响应done。发生这种情况时,它会将用户重定向到该/success页面。

现在,重要的是要记住,这是一个非常简单的方法,您需要牢记以下几点:

  1. 这些 Ajax 请求中的每一个都将阻止与您的服务器的连接,如果您使用的是 gunicorn 之类的东西,它将是一个完整的工作程序。因此,如果您的处理时间太长,或者您有很多并发用户访问此路由,则您的服务器将非常过载。

  2. 您需要正确处理错误。在我的示例中,我总是done以 a 200 OK(这是默认状态代码)返回,但是如果在处理过程中出现问题,您将返回一些不同的内容,并且可能会返回某种错误消息以显示给用户。