Flask 项目结构(最佳实践)

Flask 项目结构:从零开始搭建一个清晰的开发框架

当你第一次接触 Flask 框架时,可能只是写一个 app.py 文件,几行代码就能跑起一个本地服务器。这确实很轻量,适合快速验证想法。但随着功能越来越多,项目变得越来越臃肿,代码混乱、难以维护,这时候你就会意识到:一个合理的 Flask 项目结构,就像盖房子前的图纸,决定了整个系统的可扩展性和可维护性。

今天,我们就来手把手搭建一个适合中小型项目的 Flask 项目结构。不讲虚的,只讲实用,让你的代码不再“一团乱麻”。


为什么需要规范的 Flask 项目结构?

想象一下,你正在开发一个博客系统,功能包括用户登录、文章发布、评论管理、分类筛选。如果所有代码都写在 app.py 里,随着功能增加,这个文件会迅速膨胀到上千行。你每次改个功能,都得在几页代码中翻找,调试起来非常痛苦。

这就是“没有结构”的代价。而一个良好的 Flask 项目结构,能带来以下好处:

  • 代码职责分离,便于团队协作
  • 功能模块化,可复用性强
  • 易于测试和部署
  • 项目长期维护更轻松

所以,规范的 Flask 项目结构,是你从“写脚本”迈向“做项目”的关键一步。


推荐的 Flask 项目结构布局

下面是一个经过实践验证的典型 Flask 项目结构,适合大多数中小型 Web 应用:

my_flask_app/
│
├── app/
│   ├── __init__.py              # 初始化 Flask 应用,注册蓝图
│   ├── models.py                # 数据库模型定义(如 User、Post)
│   ├── views/                   # 视图函数(路由和处理逻辑)
│   │   ├── __init__.py
│   │   ├── auth.py              # 登录注册相关路由
│   │   ├── blog.py              # 博客文章相关路由
│   │   └── api.py               # API 接口(可选)
│   ├── static/                  # 静态文件(CSS、JS、图片)
│   ├── templates/               # HTML 模板文件
│   │   ├── base.html            # 基础模板
│   │   ├── index.html           # 首页
│   │   ├── auth/
│   │   └── blog/
│   └── utils/                   # 工具函数(如加密、邮件发送)
│       ├── decorators.py        # 自定义装饰器
│       └── helpers.py           # 常用辅助函数
│
├── config.py                    # 配置文件(开发、生产环境)
├── requirements.txt             # 依赖包列表
├── run.py                       # 启动脚本(替代直接运行 app.py)
└── .env                         # 环境变量(数据库密码、密钥等)

这个结构清晰地划分了职责:模型、视图、模板、静态资源、配置、工具函数等各司其职。


项目初始化:从创建文件夹开始

我们来一步步搭建这个结构。假设你已经安装了 Python 和 pip。

mkdir my_flask_app
cd my_flask_app
python -m venv venv
source venv/bin/activate   # Linux/Mac
pip install flask flask-sqlalchemy python-dotenv

接下来,创建项目文件和目录:

mkdir app
mkdir app/static app/templates app/views app/utils
touch config.py requirements.txt run.py .env
touch app/__init__.py app/models.py app/views/__init__.py
touch app/templates/base.html app/templates/index.html
touch app/utils/decorators.py app/utils/helpers.py

现在,你的项目结构就搭好了,接下来我们逐步填充内容。


核心配置文件:config.py 的作用

config.py 是整个应用的“心脏”,它定义了不同环境下的配置参数。比如开发环境和生产环境的数据库地址、密钥等。

import os

class Config:
    # 应用密钥,用于会话加密
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key-123456'

    # 数据库配置(使用 SQLite,适合开发)
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'
    
    # 是否自动提交数据库变更
    SQLALCHEMY_TRACK_MODIFICATIONS = False

    # 可选:邮件配置
    MAIL_SERVER = 'smtp.gmail.com'
    MAIL_PORT = 587
    MAIL_USE_TLS = True
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')

class DevelopmentConfig(Config):
    DEBUG = True

class ProductionConfig(Config):
    DEBUG = False

config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}

💡 注释:SECRET_KEY 是 Flask 会话安全的关键,不能明文写死。建议使用 os.urandom(24) 生成随机值。SQLALCHEMY_TRACK_MODIFICATIONS 关闭后可提升性能。


应用初始化:app/init.py 的职责

这个文件是 Flask 应用的入口,负责创建应用实例并注册蓝图。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import config
import os

db = SQLAlchemy()

def create_app(config_name=None):
    # 创建 Flask 应用实例
    app = Flask(__name__)
    
    # 加载配置(默认为 development)
    if config_name is None:
        config_name = os.getenv('FLASK_ENV', 'default')
    
    # 应用配置
    app.config.from_object(config[config_name])
    
    # 初始化数据库
    db.init_app(app)
    
    # 注册蓝图
    from app.views.auth import auth_bp
    from app.views.blog import blog_bp
    from app.views.api import api_bp

    app.register_blueprint(auth_bp, url_prefix='/auth')
    app.register_blueprint(blog_bp, url_prefix='/blog')
    app.register_blueprint(api_bp, url_prefix='/api')

    # 注册模板上下文处理器(让所有模板都能访问当前用户)
    @app.context_processor
    def inject_user():
        # 这里可以添加当前用户信息逻辑
        return {'user': None}

    return app

💡 注释:register_blueprint 是 Flask 模块化的核心机制。将不同功能拆分为独立蓝图,避免主应用文件臃肿。url_prefix 为每个蓝图设置统一前缀,便于管理。


模块化视图:使用蓝图组织路由

以“用户登录”功能为例,我们创建一个独立的蓝图 auth.py

from flask import Blueprint, render_template, request, redirect, url_for, flash
from werkzeug.security import generate_password_hash, check_password_hash
from app.models import User
from app import db

auth_bp = Blueprint('auth', __name__, url_prefix='/auth')

@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        
        # 查询用户
        user = User.query.filter_by(username=username).first()
        
        # 验证密码
        if user and check_password_hash(user.password, password):
            flash('登录成功!', 'success')
            return redirect(url_for('blog.index'))
        else:
            flash('用户名或密码错误', 'error')
    
    return render_template('auth/login.html')

@auth_bp.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        
        # 检查用户名是否已存在
        if User.query.filter_by(username=username).first():
            flash('用户名已存在', 'error')
            return redirect(url_for('auth.register'))
        
        # 创建新用户(密码加密存储)
        hashed_password = generate_password_hash(password)
        new_user = User(username=username, password=hashed_password)
        db.session.add(new_user)
        db.session.commit()
        
        flash('注册成功,请登录', 'success')
        return redirect(url_for('auth.login'))
    
    return render_template('auth/register.html')

💡 注释:Blueprint 让路由逻辑独立于主应用,便于复用和测试。generate_password_hash 保证密码安全存储,永远不要明文保存密码


模板与静态资源管理

模板文件放在 app/templates/,静态资源放在 app/static/

示例:app/templates/base.html(基础模板)

<!-- app/templates/base.html -->
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}我的 Flask 博客{% endblock %}</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
    <header>
        <h1>我的 Flask 博客</h1>
        <nav>
            <a href="{{ url_for('blog.index') }}">首页</a>
            <a href="{{ url_for('auth.login') }}">登录</a>
            <a href="{{ url_for('auth.register') }}">注册</a>
        </nav>
    </header>

    <main>
        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
                {% for category, message in messages %}
                    <div class="alert alert-{{ category }}">{{ message }}</div>
                {% endfor %}
            {% endif %}
        {% endwith %}

        {% block content %}{% endblock %}
    </main>
</body>
</html>

💡 注释:url_for 是 Flask 的路由反向解析机制,避免硬编码 URL。get_flashed_messages 用于显示提示信息,是 Flask 的内置功能。


启动脚本:run.py 的作用

最后,创建一个启动文件,让运行更清晰。

from app import create_app
import os

os.environ['FLASK_ENV'] = 'development'

app = create_app()

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

运行命令:

python run.py

浏览器访问 http://127.0.0.1:5000,你就能看到你的项目已成功运行。


总结:构建可持续的 Flask 项目

一个清晰的 Flask 项目结构,不是形式主义,而是对代码质量的承诺。它让你在面对复杂需求时,依然能从容应对,而不是手忙脚乱。

从今天开始,不要再把 Flask 当作“脚本工具”使用。真正把它当作一个完整的 Web 框架来构建。遵循模块化、职责分离的原则,你的项目才能走得更远。

记住:代码的整洁度,决定了你的开发效率。一个良好的 Flask 项目结构,是你迈向专业开发的第一步。

最后提醒:项目中不要硬编码敏感信息(如数据库密码、API 密钥),务必使用 .env 文件配合 python-dotenv 加载,确保安全。