Flask 教程

Flask 项目结构

当你的 Flask 应用从“Hello World”成长为一个包含数据库、用户认证、多个页面的真实项目时,把所有代码塞进一个 app.py 文件会导致代码极其臃肿且难以维护。

为了解决这个问题,Flask 社区沉淀出了一套标准的中大型项目结构。这套结构的核心思想是:模块化(蓝图)应用工厂模式


📂 标准 Flask 项目目录结构

这是一个经过生产环境验证的、结构清晰的 Flask 项目目录树:

纯文本
plaintext
my_flask_project/
│
├── app/                        # 📁 核心应用代码目录(所有业务逻辑都在这里)
│   ├── __init__.py             # 🌟 应用工厂 (create_app),项目的灵魂
│   ├── extensions.py           # 🔌 扩展实例化 (db, migrate, login_manager 等)
│   ├── models.py               # 🗄️ 数据库模型 (SQLAlchemy Models)
│   │
│   ├── main/                   # 📦 蓝图:主页面/通用路由 (如首页、关于)
│   │   ├── __init__.py         #    注册蓝图
│   │   └── routes.py           #    具体的视图函数
│   │
│   ├── auth/                   # 📦 蓝图:用户认证 (登录、注册、登出)
│   │   ├── __init__.py
│   │   └── routes.py
│   │
│   ├── api/                    # 📦 蓝图:RESTful API (前后端分离接口)
│   │   ├── __init__.py
│   │   └── routes.py
│   │
│   ├── templates/              # 🎨 HTML 模板文件 (Jinja2)
│   │   ├── base.html           #    基础布局模板
│   │   ├── main/
│   │   └── auth/
│   │
│   └── static/                 # 🖼️ 静态文件 (CSS, JS, 图片, 字体)
│       ├── css/
│       ├── js/
│       └── images/
│
├── migrations/                 # 🔄 数据库迁移文件 (由 Flask-Migrate 生成)
├── tests/                      # 🧪 单元测试和集成测试代码
│
├── config.py                   # ⚙️ 配置文件 (区分开发、测试、生产环境)
├── requirements.txt            # 📦 项目依赖包列表 (pip freeze)
├── .env                        # 🔒 环境变量 (存放密钥、数据库密码,**绝不提交到 Git**)
├── .gitignore                  # 🚫 Git 忽略文件配置
└── run.py                      # 🚀 项目启动入口文件

🧠 核心机制解析

要理解这个结构,必须掌握以下三个核心概念:

1. 应用工厂模式 (app/__init__.py)

不再使用全局的 app = Flask(__name__),而是写一个函数来“制造”应用实例。
好处:方便创建多个应用实例(例如在测试时),避免循环导入问题。

纯文本
plaintext
# app/__init__.py
from flask import Flask
from config import config_dict
from app.extensions import db, migrate

def create_app(config_name='default'):
    app = Flask(__name__)
    # 加载配置
    app.config.from_object(config_dict[config_name])

    # 初始化扩展 (绑定到 app)
    db.init_app(app)
    migrate.init_app(app, db)

    # 注册蓝图
    from app.main import main_bp
    app.register_blueprint(main_bp)

    from app.auth import auth_bp
    app.register_blueprint(auth_bp, url_prefix='/auth')

    return app

2. 扩展分离 (app/extensions.py)

为了解决 Python 的循环导入问题(例如 models.py 需要 db,而 __init__.py 需要 models),我们将扩展的实例化单独抽离出来。

纯文本
plaintext
# app/extensions.py
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager

# 先实例化,但不绑定 app
db = SQLAlchemy()
migrate = Migrate()
login_manager = LoginManager()

3. 蓝图拆分 (app/main/, app/auth/)

蓝图(Blueprint)相当于子应用。我们按功能模块而不是按文件类型来拆分代码。
每个蓝图文件夹里都有一个 __init__.py 用于创建蓝图对象,和一个 routes.py 用于写路由。

纯文本
plaintext
# app/auth/__init__.py
from flask import Blueprint

# 创建蓝图,'auth' 是蓝图名称,__name__ 帮助定位模板
auth_bp = Blueprint('auth', __name__, template_folder='../templates/auth')

# 导入路由(必须在蓝图创建后导入,避免循环引用)
from app.auth import routes 
纯文本
plaintext
# app/auth/routes.py
from app.auth import auth_bp

@auth_bp.route('/login')
def login():
    return 'Login Page'

⚙️ 配置管理 (config.py)

在实际开发中,开发环境(本地 SQLite)和生产环境(线上 MySQL/PostgreSQL)的配置是不同的。使用面向对象的方式管理配置非常优雅:

纯文本
plaintext
# config.py
import os
from dotenv import load_dotenv

# 加载 .env 文件中的环境变量
basedir = os.path.abspath(os.path.dirname(__file__))
load_dotenv(os.path.join(basedir, '.env'))

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard-to-guess-string'
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(Config):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
        'sqlite:///' + os.path.join(basedir, 'dev-data.sqlite')

class ProductionConfig(Config):
    DEBUG = False
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')

# 字典映射,方便在工厂模式中通过字符串选择配置
config_dict = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}

🚀 启动项目 (run.py)

最后,我们需要一个入口文件来启动这个工厂制造出来的应用:

纯文本
plaintext
# run.py
import os
from app import create_app

# 从环境变量读取配置,默认使用开发环境
config_name = os.getenv('FLASK_CONFIG', 'development')
app = create_app(config_name)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

运行方式:

纯文本
plaintext
python run.py

(注:在 Flask 2.2+ 中,也可以不使用 run.py,而是通过命令行 flask --app run run --debug 来启动,但保留 run.py 对很多开发者来说更直观。)


💡 最佳实践建议

  1. .env 文件极其重要:永远不要把数据库密码、SECRET_KEY 硬编码在代码里。使用 python-dotenv 库读取 .env 文件,并确保 .env 被加入了 .gitignore
  2. 模板和静态文件的位置
  • 默认情况下,Flask 会在 app/ 目录下寻找 templates/static/
  • 如果蓝图需要独立的模板,可以在创建蓝图时指定:Blueprint('auth', __name__, template_folder='templates')
  1. 保持 __init__.py 干净:应用工厂文件只负责“组装”(加载配置、初始化扩展、注册蓝图),绝对不要在里面写具体的业务路由。

掌握了这个结构,你的 Flask 项目就具备了支撑中大型商业应用的能力。接下来,你可以开始往里面填充 数据库模型 (models.py)具体的蓝图路由 了!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注