不同于大多数其他的 Web 框架,Flask 并不强制要求大型项目使用特定的组织方式,程序结构的组织方式完全由开发者决定。在此我记录一种使用包和模块组织大型程序的方式。
框架一览
重要文件说明
文件说明顺序为目录由上至下。
-
蓝图文件(
apps\index\init.py
)from flask import Blueprint index_bp = Blueprint('index', __name__, template_folder=='index') # 可以指定`template_folder`参数,指明该蓝图路由下的模板文件位置。 from . import views # 在蓝图定义之后导入,否则报循环导包错误。
-
错误处理(
apps\main\errors.py
)@main_bp.app_errorhandler(404) def page_not_found(e): return render_template('404.html') @main_bp.app_errorhandler(500) def internal_server_error(e): return render_template('500.html') # 分别处理了404、500的错误,返回指定友好页面。 # app 和 Blueprint均可以注册 `app_errorhandler`,无需访问路由。 # 碍于篇幅,403等错误页面略。
-
工厂函数实例化app(
apps\init.py
)from flask import Flask from settings import config from apps.main import main_bp from apps.index import index_bp from ext import db, mail, moment, bootstrap bp_list = [ main_bp, index_bp ] # 蓝图列表 def create_app(config_key): # 项目入口文件(manage.py)中调用该函数,并传入环境key。 app = Flask(__name__) app.config.from_object(config.get(config_key, 'development')) # 获取配置项 db.init_app(app) # 数据库初始化 bootstrap.init_app(app) # 前端页面 moment.init_app(app) # 时间模块 mail.init_app(app) # 邮件模块 for bp in bp_list: # 注册蓝图 app.register_blueprint(bp) return app # 返回实例
-
数据库管理(
db_manage.py
)from flask_migrate import Migrate, MigrateCommand from flask_script import Manager, Shell from apps.index.models import User, Role from manage import app from ext import db db_manager = Manager(app) migrate = Migrate(app, db) # 命令行工具初始化 db_manager.add_command('db', MigrateCommand) # 添加`db`迁移命令 # 集成shell工具实现无需导包,便可加载上下文对象,见下文。 def make_shell_context(): return dict(app=app, db=db, User=User, Role=Role) db_manager.add_command("shell", Shell(make_context=make_shell_context)) if __name__ == '__main__': db_manager.run()
-
集成shell工具实现无需导包,便可加载上下文对象:
(python38-flasky)>>> python db_manage.py shell C:\Users\EDZ\Desktop\flasky\flasky >>> app <Flask 'apps'> >>> db <SQLAlchemy engine=sqlite:///C:\Users\EDZ\Desktop\flasky\flasky\data-dev.sqlite> >>> User <class 'apps.index.models.User'>
-
-
工具扩展(
ext.py
)from flask_sqlalchemy import SQLAlchemy from flask_mail import Mail from flask_moment import Moment from flask_bootstrap import Bootstrap # 为了解决循环导包问题, 将扩展初始化都布置于此,方便其他模块导入,如:工厂函数模块、db_manage模块等。 mail = Mail() db = SQLAlchemy() moment = Moment() bootstrap = Bootstrap()
-
项目主文件(
manage.py
)import os from flask_script import Manager from apps import create_app # 导入工厂函数 app = create_app( os.getenv('FLASK_ENV', 'development') # 传入环境key参数,加载不同环境的配置。 ) manager = Manager(app) # 实例化命令行管理,实现命令行启动。 if __name__ == '__main__': manager.run()
-
项目配置文件(
settings.py
)import os basedir = os.path.abspath(os.path.dirname(__file__)) # 规定项目根路径,一般为app实例同级路径。 # 基础配置 class BaseConfig: # 秘钥 SECRET_KEY = 'hard to guess string' # 开发环境 class DevelopmentConfig(BaseConfig): DEBUG = True # 邮箱 MAIL_SERVER = 'smtp.qq.com' # 发送邮箱的服务地址 这里设置为QQ邮箱服务器地址 MAIL_PORT = '587' # 发送端口为465或者587 MAIL_USE_TLS = True # 端口为587对应的服务 # MAIL_USE_SSL = True # 端口为465对应的服务 二选一即可 MAIL_USERNAME = '123456789@qq.com' # 使用者的邮箱 MAIL_PASSWORD = 'asdfehigk' # 不是QQ邮箱登录密码,是QQ邮箱授权码获取,用于第三方登录验证 MAIL_DEFAULT_SENDER = '1536452582@qq.com' # 默认发送者 # 数据库 SQLALCHEMY_COMMIT_ON_TEARDOWN = True SQLALCHEMY_TRACK_MODIFICATIONS = True SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite') # 测试环境 class TestingConfig(BaseConfig): TESTING = True SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'data-test.sqlite') # 生产环境 class ProductionConfig(BaseConfig): DEBUG = False SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'data-product.sqlite') # 环境配置字典,主文件传入该字典的key,工厂函数获取key加载配置类。 config = { 'development': DevelopmentConfig, 'test': TestingConfig, 'production': ProductionConfig, 'default': DevelopmentConfig }