Flask应用源代码变化时自动重载

14 投票
3 回答
22905 浏览
提问于 2025-04-18 04:57

我知道在调试模式下,Flask会自动检测.py源代码文件的变化,并在有新请求时重新加载这些文件。

我以前在我的应用程序中经常看到这个功能。比如在views.py文件中的@app.route装饰器部分稍微改动一下文本,刷新浏览器后就能看到变化。

但是突然之间(我记不清是什么改变了),这个功能似乎不再有效了。

问:我哪里出错了?

我在一个运行OSX 10.9的系统上,使用Python 2.7并设置了虚拟环境(VENV)。我在项目根目录下用foreman start来启动它。

应用程序的结构是这样的:

[Project Root]
+-[app]
| +-__init__.py
| +- views.py
| +- ...some other files...
+-[venv]
+- config.py
+- Procfile
+- run.py

文件的样子是这样的:

# Procfile
web: gunicorn --log-level=DEBUG run:app
# config.py
contains some app specific configuration information.
# run.py
from app import app

if __name__ == "__main__":
    app.run(debug = True, port = 5000)
# __init__.py
from flask import Flask
from flask.ext.login import LoginManager
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.mail import Mail
import os

app = Flask(__name__)
app.config.from_object('config')

db = SQLAlchemy(app)

#mail sending
mail = Mail(app)

lm = LoginManager()
lm.init_app(app)
lm.session_protection = "strong"

from app import views, models
# app/views.py
@app.route('/start-scep')
def start_scep():
    startMessage = '''\
<html>
<header>
<style>
body { margin:40px 40px;font-family:Helvetica;}
h1 { font-size:40px; }
p { font-size:30px; }
a { text-decoration:none; }
</style>
</header>

<p>Some text</p>
</body>
</html>\
'''
    response = make_response(startMessage)
    response.headers['Content-Type'] = "text/html"
    print response.headers
    return response

3 个回答

5

这是一个示例应用程序,其中app是我们的应用,而这个应用保存在start.py这个文件里:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hallo():
    return 'Hello World, this is really cool... that rocks... LOL'

现在我们通过命令行启动这个应用,并加上--reload这个标志。

gunicorn -w 1 -b 127.0.0.1:3032 start:app --reload

这样,gunicorn会在文件发生变化时自动重新加载应用,根本不需要手动去改什么。

如果你想让这个应用在后台运行,可以加上-D这个标志。

gunicorn -D -w 1 -b 127.0.0.1:3032 start:app --reload

-D 表示后台模式

-w 工作进程的数量

-b 地址和端口

start (start.py) :app - 应用程序

--reload 表示gunicorn会监控文件变化

可以查看设置文件:http://docs.gunicorn.org/en/latest/settings.html

那里列出了所有选项和标志。祝你玩得开心!

6

解决办法是停止使用 foreman start,就像评论里说的那样,直接执行 python run.py

这样一来,app.run 方法里的 debug=Trueuse_reloader=True 这两个设置就能生效了。

13

这里的问题,正如其他回答所说的,似乎是你从 python run.py 切换到了 foreman start,或者你修改了你的 Procfile

# Procfile
web: python run.py

变成了

# Procfile
web: gunicorn --log-level=DEBUG run:app

当你运行 foreman start 时,它会执行你在 Procfile 中指定的命令。(我猜测你是在使用 Heroku,但即使不是,这样做也很好,因为它会模拟你在服务器/Heroku dyno/其他环境中运行的情况。)

所以现在,当你通过 foreman start 运行 gunicorn --log-level=DEBUG run:app 时,你实际上是用 gunicorn 来运行你的应用,而不是使用 Flask 自带的内置web服务器。run:app 这个参数告诉 gunicornrun.py 文件中寻找一个名为 appFlask 实例,导入它并运行。这就有趣了:因为 run.py 被导入了,所以 __name__ == '__main__' 的值是 False(想了解更多可以查看 这里),因此 app.run(debug = True, port = 5000) 这个调用就不会被执行。

这正是你想要的(至少在公开环境中是这样的),因为当调用 app.run() 时,Flask 内置的web服务器存在一些严重的安全漏洞。虽然 --log-level=DEBUG 听起来很迷惑,因为它用了“DEBUG”这个词,但它只是告诉 gunicorn 哪些日志信息需要打印,哪些可以忽略(可以查看 Python的日志文档)。

解决方案是,当你在本地运行和调试应用时,使用 python run.py,而只有在想要模拟生产环境时才使用 foreman start。另外,由于 gunicorn 只需要导入 app 对象,你可以消除一些歧义,将你的 Procfile 改为

# Procfile
web: gunicorn --log-level=DEBUG app:app

你也可以看看 Flask Script,它有一个内置命令 python manage.py runserver,可以在调试模式下运行 Flask 的内置web服务器。

撰写回答