刚接触Flask,它的一大特色简直不要太吸引人——5行代码写一个服务
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return 'hello world!'
if __name__ == '__main__':
app.run()
然而这么简单的启动方法居然被弃用了,还有王法吗?还有法律吗?
下面是一个简陋的项目文件结构
test_flask:项目根目录
TestFlask:主应用包
.flaskenv:存储用于Flask的环境变量
Pipfile、Pipfile.lock、.venv:当前项目虚拟环境
TestFlask.__init__.py文件内容
from flask import Flask
def create_app(config_name=None):
app = Flask('TestFlask')
return app
.flaskenv文件内容
FLASK_APP=TestFlask
FLASK_ENV=development
然后在pipenv虚拟环境中安装 python-dotenv(不知道怎么用pipenv的花5分钟看下https://blog.csdn.net/weixin_40283460/article/details/114377930)
pipenv install python-dotenv
最后配置一个启动配置
然后运行刚才配置的启动项就可以跑起来了
Flask是怎么发现项目那个地方有app(应用实例)的呢?
flask run命令执行时,会根据自动发现机制寻找应用实例:
如果废了这么大劲只是为了换个姿势启动,那是和脱裤子放P没啥区别
所以换个姿势,是为了找个更好的角度发力
方便测试和部署
不用写死配置,而是通过工厂函数,可以在不同的环境(开发、测试、生产),传入对应的参数,从而根据不同的配置创建应用实例,实现配置隔离的效果
工厂函数
def create_app(config_name=None):
if config_name is None:
config_name = os.getenv('FLASK_CONFIG', 'development')
app = Flask('bluelog')
app.config.from_object(config[config_name])
配置模块
class BaseConfig(object):
...
class DevelopmentConfig(BaseConfig):
...
class TestingConfig(BaseConfig):
...
class ProductionConfig(BaseConfig):
...
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig
}
管理注册的扩展
当程序注册的扩展比较多时,通过在工厂函数中实现扩展的初始化,和在extensions.py模块中实现扩展的实例化,可以将扩展的引入动作模块化,结构更清晰,方便管理
在工厂函数中
def create_app(config_name=None):
app = Flask('bluelog')
...
register_extensions(app)
...
return app
def register_extensions(app):
bootstrap.init_app(app)
db.init_app(app)
login_manager.init_app(app)
csrf.init_app(app)
ckeditor.init_app(app)
mail.init_app(app)
moment.init_app(app)
toolbar.init_app(app)
migrate.init_app(app, db)
在extensions.py模块中
bootstrap = Bootstrap()
db = SQLAlchemy()
login_manager = LoginManager()
csrf = CSRFProtect()
ckeditor = CKEditor()
mail = Mail()
moment = Moment()
toolbar = DebugToolbarExtension()
migrate = Migrate()
项目其他地方需要使用扩展从extensions.py模块中引入,但是由于扩展的初始化是在工厂函数中完成的,所以扩展的后续使用也需要在程序上下文激活的环境使用
命令行参数
flask run命令和app.run()方法底层都是调用run_simple方法,所以原先通过run()方法传参实现的功能也可以通过命令行传参实现
-h, --host TEXT The interface to bind to.
-p, --port INTEGER The port to bind to.
--cert PATH Specify a certificate file to use HTTPS.
--key FILE The key file to use when specifying a
certificate.--reload / --no-reload Enable or disable the reloader. By default
the reloader is active if debug is enabled.--debugger / --no-debugger Enable or disable the debugger. By default
the debugger is active if debug is enabled.--eager-loading / --lazy-loader
Enable or disable eager loading. By default
eager loading is enabled if the reloader is
disabled.--with-threads / --without-threads
Enable or disable multithreading.
--extra-files PATH Extra files that trigger a reload on change.
Multiple paths are separated by ';'.--help Show this message and exit.