How to prevent freezing in Flask web app during computations and redirect upon completion? (Python)

huangapple go评论65阅读模式
英文:

How to prevent freezing in Flask web app during computations and redirect upon completion? (Python)

问题

我正在使用Python 3.11编写一个Flask Web应用程序,我希望实现以下功能:

  1. 客户端提交数据,服务器返回一个带有加载动画的不同HTML页面。

  2. 服务器开始处理数据,而客户端仍然可以像往常一样使用Web应用程序,即Web应用程序不会因为计算而冻结。

  3. 计算完成后,客户端被重定向到包含处理数据结果的页面。

我遇到的问题是如何使服务器在提交数据时返回新的HTML页面,然后开始计算而不会导致客户端冻结,然后重定向到结果页面。

顺便说一下,我对Flask非常陌生。

我尝试在单独的线程中运行包含计算的函数,然后返回加载页面,但然后我需要在计算完成时将客户端重定向到另一个页面,但我得到了很多错误,因为客户端没有请求任何内容(这是我的猜测,但我没有收到明确指出的错误),并且因为它在app_context之外运行(我对app_context一无所知)。

好的,这是很多解释,我知道你在想什么,为什么不只是进行计算然后返回包含完成结果的结果页面呢?那是因为我希望界面看起来很好,网站感觉响应迅捷和稳定,而且我想练习使用Bootstrap。因此,如果我不先返回加载页面,页面将保持不变,用户可能无法理解数据已提交并且服务器已开始处理它。加载页面添加了Bootstrap旋转器并禁用了数据输入/表单。

现在提供一些额外的信息,以使问题更容易解决:

什么? 信息
操作系统 Windows 11
Python版本 3.11
服务器 本地主机

注意:我正在一个单独的文件中编写Web应用程序的这一部分,该文件具有可用于注册路由的已注册蓝图,因此对我来说无法使用app变量。(app变量通常具有Flask()类)

现在转到代码,请记住以下代码是MRE(最小可复制示例),为了使您能够轻松运行它,因此app变量存在,但在我的代码中对我不可用。

要下载所有必要的文件(main.py和包含HTML文件的templates文件夹):点击这里(GitHub)

import random
import time
import threading
from flask import Flask, render_template, request, redirect, url_for

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def home():
    if request.method == 'POST':
        file = request.files['file']
        process_thread = threading.Thread(target=example_processing, args=(file,), daemon=True)
        process_thread.start()
        return render_template("processing.html")

    return render_template("home.html")


def example_processing(file):
    # 示例处理所需的时间(不是实际处理)
    time.sleep(random.randint(3, 7))
    return redirect(url_for("ranking"))


@app.route("/ranking")
def ranking(filename):
    return render_template("ranking.html")

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

请记住,上面的代码不是可工作的代码,当您上传一个文本文件时,会出现错误,但它可以让您了解我想要做什么。

还要记住,我没有app变量可用,所以无法使用with app.app_context()

为了澄清,问题出在重定向上。

我知道这可能是一个困难的问题,也知道我可能没有让一切都变得很清晰,但我已经尽力使这个问题尽可能容易解决,这是我第三个Flask程序,所以我对Flask还很新。

谢谢。

英文:

I am coding a Flask web app in Python 3.11 and I want to make the following possible:

  1. Client submits data and the server returns a different HTML page with a loading animation

  2. The server starts processing the data while the client can still use the web app as usual, basically the web app not freezing because of the computation.

  3. The computation is finished and the client gets redirected to a page with the results of the processed data.

The problem I am having is how to make the server return a new HTML page when data is submitted and then start computing without the client-side freezing while computing, and then redirecting to the results page.

By the way, I'm very new to Flask.

I have tried to run the function (where the computation happens) inside a separate thread and then return the loading page, but then I need to redirect the client to another page when the computation is finished but then I get lots of errors because the client isn't requesting anything (that is my guess but I don't get any errors specifically saying that), and because it is running outside of the app_context (I don't know anything about app_context ).

Ok, that was a lot of explanation and I know what you're thinking, why not just do the computation and then return the results page with the finished results? Well, that's because I want the UI to look very good and the website to feel responsive and stable, also I want to practice using Bootstrap. Therefore If I wouldn't first return the loading page, the page would just look the same and the user would maybe not understand that the data was submitted and the server has started processing it. The loading page adds a Bootstrap spinner and disables the data entry/form.

Now some extra info to make the problem a little bit easier to solve:

What? Info
OS Windows 11
Python Version 3.11
Server Localhost

Note: I am coding this part of my web app in a separate file that has a registered blueprint available to register route's, therefor the app variable is not available to me. (The app variable normally has the Flask() class)

Now over to the code, please keep in mind that the following code is a MRE (Minimal Reproducible Example) To make it as easy as possible for you to run it, and therefor the app variable is there but in my code it is not available to me.

To download all nescessary files (main.py and templates folder with html files): Click Here (GitHub)

import random
import time
import threading
from flask import Flask, render_template, request, redirect, url_for

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def home():
    if request.method == 'POST':
        file = request.files['file']
        process_thread = threading.Thread(target=example_processing, args=(file,), daemon=True)
        process_thread.start()
        return render_template("processing.html")

    return render_template("home.html")


def example_processing(file):
    # Example of the time the processing takes (not the actual processing I am going to do)
    time.sleep(random.randint(3, 7))
    return redirect(url_for("ranking"))


@app.route("/ranking")
def ranking(filename):
    return render_template("ranking.html")

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

Remember that the code over is not working code, when you upload a Txt file you will get errors but it gives you an idea of what I want to do.

Also, remember that I do not have the app variable available so I cannot use with app.app_context():

To clarify, the problem is the redirecting.

I know that this may be a difficult question and that I maybe haven't made everything so clear but I have tried my best to make this question as easy as possible to solve and this is my third Flask program so I am pretty new to Flask.

Thank You.

答案1

得分: 1

最简单的方法是通过异步调用(ajax请求)来实现。

  1. 用户点击表单的提交按钮。

  2. 通过JavaScript,你拦截提交并显示一个忙碌的图标(或者你希望显示你正在处理请求的任何内容)。

  3. 然后,你通过Ajax(异步请求)将表单的内容提交到你的服务器。

  4. 当服务器处理完成时,它会返回一个结果给你的代码。然后你可以移除忙碌图标,以及进行任何其他操作 - 显示返回的结果,将用户重定向到另一个页面并在那里显示结果,等等。

在你的场景中,你想要的是 - 服务器完成处理并将结果存储在某个地方(会话内存、内存缓存或数据库中),然后服务器返回类似于 'success' 的东西给调用服务器的JavaScript代码。然后,你的JavaScript代码移除忙碌图标并重定向到一个Flask端点,该端点读取你保存的服务器输出并将这个值返回给用户。

英文:

The simplest way to do this is via Asynchronous calls (ajax requests).

  1. User clicks the submit button of a form.

  2. Via javascript, you intercept the submit and display a busy icon (or whatever you wish to show you're working on the request)

  3. You then submit the contents of the form via Ajax (asynchronous request) to your server.

  4. When server is done processing, it returns a result to your code. You can then remove the busy icon and do whatever else you want - display the returned result, redirect the user to another page and display the result there, etc

In your scenario, what you want is - server finishes processing and stores the results somewhere (in session memory, memcache or a DB), then the server returns something like 'success' to your javascript code that called the server. Your javascript code then removes the busy icon and redirects to a flask endpoint which reads the output from the server that you'd saved and returns this value to the user.

huangapple
  • 本文由 发表于 2023年7月17日 23:21:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76705938.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定