前面我们了解了 Flask 框架的特性和一些用法,比如创建一个简单应用、做些页面,以及增加鉴权模块等,如果要将 Flask 用于实际项目开发,还需要了解一下 Flask 项目结构。 Flask 是一个轻量级的 Web 框架,扩展性强,灵活性高,容易上手,不过 Flask 没有给出明确的项目结构,而是让开发者根据实际需求,创建适合自己的项目结构。对于初学者来说,面临的困难可能是不知道如何组织代码,特别是在看一些别人的代码时,弄不清结构,对理解和学习造成一定障碍。 需要说明的是今天所介绍的结构并不是最好的,不同的项目,不同的团队,不同的理念,会有不同的结构,今天介绍的只是一个参考。 我们就那之前的 Flask数据持久化 章节的练习作为实践。 按功能组织按功能,指的是将 Web 项目的不同职能划分开,比如路由部分、模型部分、业务逻辑部分等 目录结构project/ forms/ myform.py ... models/ __init__.py profile.py user.py ... routes/ __init__.py home.py profile.py ... static/ ... services/ __init__.py ... templates/ createprofile.html profile.html ... __init__.py config.py 可以看到,项目根目录下,分为:
这样的分类,相当于将之前写到一个代码文件(app.py)中的逻辑,按功能划分开,当项目逐渐变大变复杂后,这样的划分有助于开发和维护 初始化按功能划分开,比较容易理解,不过将分开的部分有机结合起来是个问题, 推荐的方式是,在每个目录下创建一个
初始化模型数据模型放在 首先,创建目录的 from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def init_app(app): db.init_app(app) return db
模型代码示例 from . import db
class Profile(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20)) birthday = db.Column(db.Date()) createtime = db.Column(db.DateTime()) about = db.Column(db.Text())
初始化路由当路由处理代码被分开之后,在主程序代码中初始化会变得比较麻烦,幸好 Flask 有个 blueprint(蓝图)的概念,能很好的将分离出来的代码管理起来,确切的说 blueprint 的作用不止于此,这里只是需要用到它的部分功能
路由处理定义示例, from flask import Blueprint
home_bp = Blueprint('home_bp', __name__)
@home_bp.route('/', methods=['GET', 'POST']) def index(): return "Hello World!", 200
再看看路由模块的初始化, from .home import home_bp from .profile import profile_bp
def init_app(app): app.register_blueprint(home_bp) app.register_blueprint(profile_bp)
Flask app 工厂方法在之前的介绍中,在
创建 Flask app 写在 from flask import Flask from .config import config from . import models, routes
def create_app(config_name='default'): app = Flask(__name__) app.config.from_object(config[config_name]) config[config_name].init_app(app)
models.init_app(app) routes.init_app(app)
return app
工厂方法比单个文件写法更清爽,修改起来也更简单,另外这样定义还可以避免循环依赖问题,
启动项目通过工厂方法创建的应用,因为没有明确的 正常启动启动之前,需要先设置 FLASK_APP 环境变量,指定需要运行的 Flask 项目, 值为项目文件夹名,即项目名:
export FLASK_APP=project
set FLASK_APP=project
$env:FLASK_APP="project" 然后在项目目录的上一层目录下执行命令,启动项目: flask run 如果一切正常,就可以看到类似的结果: * Serving Flask app "project" * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) 设置启动参数前面工厂方法可以定义一些参数,如何来指定呢?其中一种方法是设置环境变量
export FLASK_APP=project:create_app('testing')
set FLASK_APP=project:create_app('testing')
$env:FLASK_APP="project:create_app('testing')"
您可能已经想到,这种方式可以解决工厂方法名不是默认 export FLASK_APP=project:myapp_factory() 按业务组织一个大型项目中,会包含很多子业务,比如人员管理、订单管理、统计报表等等,每一部分都可以是独立的项目,在 Flask 中,按照业务的方式将文件划分开,就是按业务方式来组织项目结构,这样的组织方式有助于并行开发和分而治之。 大体的结构是: project/ __init__.py config.py db.py auth/ __init__.py route.py models.py templates/ blog/ __init__.py route.py models.py templates/ ...
按业务组织方式中,每个子业务都是以 blueprint 的方式注册到 Flask app 上的,在按功能组织的方式中,我们只将路由用 blueprint 注册了,其实可以将 blueprint 看成一个独立的 Flask app,不过不用真的去部署,只需要注册到真正的 Flask app 上就行。 项目配置之前的练习中都是将配置写到 Python 中提供了丰富的配置处理方式,今天就 Flask 的配置利用实例简单介绍下,不过介绍的不见得就是最好的,只是一种解决思路,大家可以根据具体项目有所调整。 看一下代码: import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config: SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string' SQLALCHEMY_COMMIT_ON_TEARDOWN = True
@staticmethod def init_app(app): pass
class DevelopmentConfig(Config): DEBUG = True SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data-dev.db')
class TestingConfig(Config): TESTING = True SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data-test.db')
class ProductionConfig(Config): SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data.db')
config = { 'development': DevelopmentConfig, 'testing': TestingConfig, 'production': ProductionConfig,
'default': DevelopmentConfig }
有必要说明的是,Flask app 有多种设置配置的方式,常用的如:
总结今天介绍了一个简单的 Flask 项目化结构,并利用之前做过的数据持久化的练习,做了项目化后的代码说明,并且说明了按功能和按业务两种项目组织方式,最后介绍了 Flask 项目中配置的方式。总之 Flask 是一个宽松的,简单的 Web 框架,每个人都可打造自己的一套项目构建方式,不过对于刚开始接触的同学,或者为了交流方便,还是有必要了解一下一般的组织方式,希望对您有所启发。 最后,示例代码中提供了较为完整的例子,其中还有如何自定义数据库初始化命令的例子,请您参考。 参考
第124天:Web 开发 Django 模板第123天:Web 开发 Django 管理工具第122天:Flask 单元测试 |
|