Flask应用源代码变化时自动重载
我知道在调试模式下,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 个回答
这是一个示例应用程序,其中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
那里列出了所有选项和标志。祝你玩得开心!
解决办法是停止使用 foreman start
,就像评论里说的那样,直接执行 python run.py
。
这样一来,app.run
方法里的 debug=True
和 use_reloader=True
这两个设置就能生效了。
这里的问题,正如其他回答所说的,似乎是你从 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
这个参数告诉 gunicorn
去 run.py
文件中寻找一个名为 app
的 Flask
实例,导入它并运行。这就有趣了:因为 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服务器。