软硬件环境
- windows 10 64bit
- anaconda3 with python 3.7
- pycharm 2020.1.2
- flask 1.1.2
项目结构
前言
前面的内容,在我们的示例中,除了模板文件以外,其它的python代码都是写在了同一个py文件当中,这里面包含了视图函数、数据库模型、应用的配置等等。在小的示例中,这样写问题不大,但是在实际项目中,这样肯定是不行的。
项目结构
Flask是一个轻量级的Web框架,扩展性强,灵活性高,容易上手,不过Flask并没有给出明确的项目结构,而是让开发者根据实际需求,创建适合自己的项目结构。需要说明的是本文所介绍的项目结构可能并不是最好的,仅仅是一个参考,不同的项目,不同的团队,不同的理念,会有不同的项目结构
project/
forms/
myform.py
...
models/
__init__.py
mymodel.py
...
routes/
__init__.py
myroute.py
...
static/
...
services/
__init__.py
...
templates/
index.html
...
__init__.py
config.py
manage.py
其中
- forms(表单): 存放表单对象
- models(模型): 存放数据模型,即库表在程序中的映射对象,以及对象之间的关系
- routes(路由): 存放请求路由以及处理逻辑
- static(静态文件):
flask约定存放静态文件的目录 - templates(模板):
flask约定存放页面模板的目录 - services(服务): 存放业务逻辑或者其他服务类功能
- init.py:
flaskapp初始化方法 - config.py: 项目配置文件
- manage.py: 启动一个开发服务器,但是不会在生产环境中用到
蓝图
什么是蓝图
蓝图(blueprint)提供了模块化管理程序路由的功能,使程序结构清晰、简单易懂。blueprint对象和flask应用对象的工作方式很像,但他俩不是一个东西。蓝图很好地简化了大型应用工作的方式,并提供给flask扩展在应用上注册操作的核心方法。
应用工厂函数
前面讲到常见flask项目结构时提到一点,在单个文件中开发应用很方便,但是有个很大的缺点,应用在全局作用域中创建,无法动态修改配置。运行脚本时,应用实例已经创建,再修改配置已经为时已晚。面对这个问题,解决方案就是延迟创建应用实例,这时工厂函数就出场了,来看下面的示例
from flask import Flask
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from app.config import Config
bootstrap = Bootstrap()
db = SQLAlchemy()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
bootstrap.init_app(app)
db.init_app(app)
return app
首先导入了大多数正在使用的flask扩展,但是由于尚未初始化所需的应用实例,所以创建扩展类时没有向构造函数传入参数,因此扩展并未真正初始化。create_app函数是应用的工厂函数,接受一个参数,是应用使用的配置名。配置类在config.py文件中定义。应用创建并配置好后,就能初始化扩展了。在之前创建的扩展对象上调用init_app()便可以完成初始化
为什么使用蓝图
来看看蓝图的优点,来自官方文档
- 把一个应用分解为一个蓝图的集合。这对大型应用是理想的。一个项目可以实例化一个应用对象,初始化几个扩展,并注册一集合的蓝图
- 以
URL前缀和/或子域名,在应用上注册一个蓝图。URL前缀/子域名中的参数即成为这个蓝图下的所有视图函数的共同的视图参数(默认情况下) - 在一个应用中用不同的
URL规则多次注册一个蓝图 - 通过蓝图提供模板过滤器、静态文件、模板和其它功能。一个蓝图不一定要实现应用或者视图函数。
- 初始化一个
Flask扩展时,在这些情况中注册一个蓝图
蓝图作为flask层提供分割的替代,共享应用配置,并且在必要情况下可以更改所注册的应用对象。它的缺点是你不能在应用创建后撤销注册一个蓝图而不销毁整个应用对象。
蓝图示例
结合上面的应用工厂和蓝图,我们来看看示例,工程结构如下
blueprint/
app/
static/
...
views/
index.py
templates/
...
__init__.py
config.py
manage.py
README.md
requirements.txt
其中manage.py代码如下
from app import create_app
if __name__ == '__main__':
app = create_app()
app.run(use_reloader=True, port=5000)
__init__.py代码如下
from flask import Flask
from .views.index import index_blueprint
from . import config
def create_app():
app = Flask(__name__)
app.config.from_object(config)
app.register_blueprint(index_blueprint)
return app
index.py源码如下
from flask import Blueprint
index_blueprint = Blueprint('index', __name__)
@index_blueprint.route('/')
def index():
return "Hello blueprint."
config.py存放的是相关的配置信息
DEBUG = False
当上述项目启动后,我们就可以访问http://127.0.0.1:5000,浏览器输出Hello blueprint.
如何组织蓝图
flask中同样没有规定你如何来组织蓝图。常见的,有按照功能(functional)和按照分区(divisional)这2种方式来组织。
在功能架构中,按照每部分代码的功能来组织你的应用。所有模板、静态文件和视图都单独放在一个文件夹中,如下
project/
app/
__init__.py
static/
templates/
home/
admin/
views/
__init__.py
home.py
admin.py
models.py
config.py
README.md
requirements.txt
manage.py
除了project/app/views/__init__.py,在project/app/views/文件夹中的每一个.py文件都是一个蓝图。在project/app/__init__.py中,加载这些蓝图并在flask对象中注册。
而在分区式架构中,按照每一部分所属的蓝图来组织你的应用。所有的模板、视图和静态文件放在一个文件夹中。项目结构如下
project/
app/
__init__.py
admin/
__init__.py
views.py
static/
templates/
home/
__init__.py
views.py
static/
templates/
models.py
config.py
README.md
requirements.txt
manage.py
在上面的分区式结构,每一个project/app/之下的文件夹都是一个独立的蓝图。所有的蓝图通过顶级的__init__.py注册到flask对象中。
至于说,上面两种结构孰优孰劣,这个没有定论。一般的建议是这样的:
- 如果应用是由独立的且仅仅共享模型和配置的各组件组成,建议选择分区式;
- 如果应用的组件之间联系较为紧密,则建议使用功能式架构。