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接口,到时候你会看到,有了这个架子,写业务代码就像搭积木一样简单。