3、Flask项目初始化:应用工厂模式与蓝图设计
好,咱们正式开始搭建项目骨架。这一章我打算聊聊Flask项目初始化时,我个人觉得最重要的三个东西:应用工厂模式、蓝图模块化设计,还有配置管理。说白了,就是怎么让你的项目从一开始就规规矩矩,别写着写着变成一团乱麻。
3.1 为什么需要应用工厂模式?
你想想看,一个Flask应用如果直接在全局创建app = Flask(__name__),那测试怎么办?多环境部署怎么办?我在项目中遇到过好几次,因为全局app对象导致单元测试互相污染,查了半天才发现是配置没重置。
应用工厂模式,说白了就是一个函数,专门用来创建Flask应用实例。每次调用都生成一个全新的app,干净利落。
核心思路:把app的创建过程封装成一个函数,这个函数接收配置参数,返回一个配置好的Flask实例。
# project/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app(config_name='default'):
"""应用工厂函数"""
app = Flask(__name__)
# 加载配置
app.config.from_object(config[config_name])
# 初始化扩展
db.init_app(app)
# 注册蓝图
register_blueprints(app)
return app
def register_blueprints(app):
"""集中注册所有蓝图"""
from .views import customer_bp
app.register_blueprint(customer_bp, url_prefix='/api/customers')
嗯,这里要注意:db对象是在函数外部创建的,但真正绑定到app是在init_app()时。这种延迟初始化模式,是Flask扩展的标配做法。
3.2 蓝图(Blueprint)模块化设计
蓝图是什么?我习惯把它理解成「子应用」。一个大型项目可以拆成多个蓝图,每个蓝图负责一块业务。比如客户管理、订单管理、用户管理,各占一个蓝图。
这样做的好处很明显:
- 职责清晰:每个蓝图只管自己的路由和视图
- 便于复用:蓝图可以像插件一样插到不同项目里
- 团队协作:不同人开发不同蓝图,互不干扰
我的习惯:每个蓝图单独一个文件夹,里面放views.py、models.py、forms.py。这样找代码特别快,不用在整个项目里翻来翻去。
# project/views/customer.py
from flask import Blueprint, jsonify, request
customer_bp = Blueprint('customer', __name__)
@customer_bp.route('/list')
def list_customers():
"""获取客户列表"""
# 这里写业务逻辑
return jsonify({'customers': []})
@customer_bp.route('/detail/<int:customer_id>')
def customer_detail(customer_id):
"""获取客户详情"""
return jsonify({'customer_id': customer_id})
我曾经犯过一个错:把所有路由都写在app.py里,结果项目到2000行时,找个接口要翻半天。后来用蓝图重构,每个模块独立文件,清爽多了。
3.3 配置管理:开发/生产环境分离
配置管理这块,说白了就是不同环境用不同参数。开发环境用SQLite,生产环境用MySQL;开发环境开调试模式,生产环境关掉。这些不能写死在代码里。
我推荐用类的方式组织配置:
# project/config.py
import os
class Config:
"""基础配置"""
SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key'
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
"""开发环境"""
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///dev.db'
class ProductionConfig(Config):
"""生产环境"""
DEBUG = False
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'mysql://user:pass@localhost/prod_db'
config = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
注意:生产环境的密钥、数据库密码绝对不能硬编码。我见过有人把密码直接写在config.py里然后上传到GitHub...嗯,后果很严重。
启动时指定环境:
# run.py
from project import create_app
app = create_app('development') # 开发环境
# app = create_app('production') # 生产环境
if __name__ == '__main__':
app.run()
3.4 完整的项目结构
把上面这些整合起来,一个标准的Flask项目结构大概长这样:
customer_management/
├── project/
│ ├── __init__.py # 应用工厂
│ ├── config.py # 配置管理
│ ├── models/ # 数据模型
│ │ └── customer.py
│ ├── views/ # 蓝图视图
│ │ └── customer.py
│ └── templates/ # 模板文件
├── tests/ # 测试代码
├── run.py # 启动入口
└── requirements.txt # 依赖清单
这个结构我用了好几年,从几十行的小工具到上万行的企业项目都扛得住。你想想看,如果一开始就按这个架子搭,后面加功能、改配置、写测试,是不是顺手很多?
3.5 避坑指南
最后分享几个我踩过的坑:
- 循环导入:蓝图和app互相引用时容易出这个问题。解决办法是把
db等扩展单独放一个文件,蓝图里只导入db,不导入app。 - 配置覆盖:多个蓝图可能设置相同的配置项,后加载的会覆盖前面的。我建议在应用工厂里统一配置,蓝图里只做路由注册。
- 环境变量:开发环境可以用.env文件,但生产环境一定要用系统环境变量或配置中心。我曾经因为.env文件没被gitignore,导致测试数据库被清空...说多了都是泪。
总结一下:应用工厂模式让app创建可控,蓝图让业务模块化,配置管理让环境切换无痛。这三板斧砍下去,项目基础就稳了。
下一章咱们开始写客户数据的CRUD接口,到时候你会看到,有了这个架子,写业务代码就像搭积木一样简单。