Flask vs FastAPI
Flask vs FastAPI:Python 两大主流框架项目架构详解
拆解 Flask 与 FastAPI 的项目目录结构、核心逻辑代码,并对比两者的架构差异与选型建议
目录
一、前言:为什么是这两个框架
Flask 适合灵活的传统 Web 应用,FastAPI 则是现代 API / 微服务 / AI 工程服务的首选。
二、Flask 项目架构详解
2.1 架构设计理念
Flask 是微框架,核心只提供路由、模板等基本功能,项目结构需要自己设计。典型设计流程是:
数据库设计 → 架构设计 → 代码实现
2.2 推荐项目结构
flasky/
├── app/ # Flask 程序主目录
│ ├── __init__.py # 应用工厂 create_app()
│ ├── models.py # 数据模型
│ ├── email.py # 异步邮件服务
│ ├── main/ # 蓝图
│ │ ├── __init__.py # 创建蓝图对象
│ │ ├── views.py # 视图函数(路由)
│ │ ├── errors.py # 错误处理
│ │ └── forms.py # 表单定义
│ ├── static/ # 静态文件
│ └── templates/ # HTML 模板
├── settings/ # 配置目录
│ ├── dev.py # 开发环境配置
│ └── prop.py # 生产环境配置
├── filter/
│ └── requestFilter.py # 全局路由拦截器
├── migrations/ # 数据库迁移脚本
├── tests/ # 单元测试
├── config.py # 基础配置
├── manage.py # 启动入口
└── requirements.txt
2.3 核心逻辑代码
① 应用工厂(app/__init__.py)
创建 Flask 应用并加载配置(MySQL、Redis 等):
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from app.main import main_bp
db = SQLAlchemy()
def create_app(config_name='dev'):
app = Flask(__name__)
# 加载配置
if config_name == 'dev':
from settings.dev import Config
else:
from settings.prop import Config
app.config.from_object(Config)
# 初始化扩展
db.init_app(app)
# 注册蓝图(蓝图中的路由此时才真正生效)
app.register_blueprint(main_bp)
# 注册全局请求拦截器
from filter.requestFilter import register_filter
register_filter(app)
return app
② 蓝图(app/main/__init__.py)
蓝图中定义的路由处于“休眠”状态,直到注册到程序上才生效:
from flask import Blueprint
main_bp = Blueprint('main', __name__)
from app.main import views, errors # 避免循环导入,必须放最后
③ 数据模型(app/models.py)
from app import db
from datetime import datetime
class Article(db.Model):
__tablename__ = 'articles'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(128), nullable=False)
content = db.Column(db.Text)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
category = db.relationship('Category', backref='articles')
class Category(db.Model):
__tablename__ = 'categories'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
④ 视图函数(app/main/views.py)
from flask import render_template, request, jsonify
from app import db
from app.main import main_bp
from app.models import Article, Category
from app.main.forms import ArticleForm
@main_bp.route('/')
def index():
articles = Article.query.order_by(Article.created_at.desc()).all()
return render_template('index.html', articles=articles)
@main_bp.route('/api/articles', methods=['POST'])
def create_article():
form = ArticleForm()
if form.validate_on_submit():
article = Article(
title=form.title.data,
content=form.content.data
)
db.session.add(article)
db.session.commit()
return jsonify({'code': 0, 'msg': 'success', 'data': {'id': article.id}})
return jsonify({'code': 1, 'msg': '参数校验失败'})
⑤ 全局拦截器(filter/requestFilter.py)
from flask import request, jsonify
def register_filter(app):
@app.before_request
def log_request():
print(f"[{request.method}] {request.path} from {request.remote_addr}")
⑥ 启动入口(manage.py)
from app import create_app, db
app = create_app('dev')
if __name__ == '__main__':
with app.app_context():
db.create_all()
app.run(host='0.0.0.0', port=5000, debug=True)
三、FastAPI 项目架构详解
3.1 架构设计理念
FastAPI 基于标准 Python 类型提示构建,底层由 Starlette(Web 部分)+ Pydantic(数据部分)驱动,核心特点:
- 高性能:可与 NodeJS 和 Go 媲美
- 开发效率:提升约 200%~300%
- 减少 Bug:减少约 40% 人为错误
- 自动文档:部署后访问
/docs(Swagger UI)或/redoc即可看到交互式文档
3.2 推荐项目结构
fastapi_project/
├── app/
│ ├── main.py # 应用入口
│ ├── core/
│ │ ├── config.py # Pydantic Settings 配置
│ │ └── database.py # 异步数据库连接
│ ├── models/ # SQLAlchemy ORM 模型
│ │ └── article.py
│ ├── schemas/ # Pydantic 请求/响应模型
│ │ └── article.py
│ ├── crud/ # 数据库 CRUD 操作层
│ │ └── article.py
│ ├── api/
│ │ └── v1/
│ │ ├── api.py # 路由汇总
│ │ └── endpoints/
│ │ └── article.py
│ └── dependencies.py # 依赖注入
├── tests/
└── requirements.txt
3.3 核心逻辑代码
① 配置(app/core/config.py)
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
APP_NAME: str = "MyAPI"
DATABASE_URL: str = "sqlite+aiosqlite:///./app.db"
DEBUG: bool = True
class Config:
env_file = ".env"
settings = Settings()
② ORM 模型(app/models/article.py)
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey
from sqlalchemy.orm import relationship, DeclarativeBase
from datetime import datetime
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = "articles"
id = Column(Integer, primary_key=True)
title = Column(String(128), nullable=False)
content = Column(Text)
category_id = Column(Integer, ForeignKey("categories.id"))
created_at = Column(DateTime, default=datetime.utcnow)
③ Pydantic 模型(app/schemas/article.py)
这是 FastAPI 解决“字段随便传”痛点的关键:
from pydantic import BaseModel, Field
from datetime import datetime
from typing import Optional
# 请求模型:自动校验参数
class ArticleCreate(BaseModel):
title: str = Field(min_length=3, max_length=128)
content: Optional[str] = None
category_id: int = Field(gt=0)
# 响应模型:精确控制输出字段
class ArticleResponse(BaseModel):
id: int
title: str
content: Optional[str]
created_at: datetime
class Config:
from_attributes = True # 支持从 ORM 对象转换
④ CRUD 层(app/crud/article.py)
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.models.article import Article
from app.schemas.article import ArticleCreate
async def create_article(db: AsyncSession, data: ArticleCreate) -> Article:
article = Article(**data.model_dump())
db.add(article)
await db.commit()
await db.refresh(article)
return article
async def get_articles(db: AsyncSession, skip: int = 0, limit: int = 20):
result = await db.execute(select(Article).offset(skip).limit(limit))
return result.scalars().all()
async def get_article(db: AsyncSession, article_id: int):
result = await db.execute(select(Article).where(Article.id == article_id))
return result.scalar_one_or_none()
⑤ 端点路由(app/api/v1/endpoints/article.py)
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db
from app.crud import article as crud
from app.schemas.article import ArticleCreate, ArticleResponse
router = APIRouter(prefix="/articles", tags=["文章管理"])
@router.post("", response_model=ArticleResponse, status_code=status.HTTP_201_CREATED)
async def create_article(data: ArticleCreate, db: AsyncSession = Depends(get_db)):
"""创建文章(参数自动校验,类型不合法直接返回 422)"""
return await crud.create_article(db, data)
@router.get("", response_model=list[ArticleResponse])
async def list_articles(skip: int = 0, limit: int = 20, db: AsyncSession = Depends(get_db)):
return await crud.get_articles(db, skip=skip, limit=limit)
@router.get("/{article_id}", response_model=ArticleResponse)
async def get_article(article_id: int, db: AsyncSession = Depends(get_db)):
article = await crud.get_article(db, article_id)
if not article:
raise HTTPException(status_code=404, detail="文章不存在")
return article
⑥ 应用入口(app/main.py)
from fastapi import FastAPI
from app.api.v1.api import api_router
from app.core.database import engine
from app.models.article import Base
app = FastAPI(
title="Article API",
description="文章管理系统",
version="1.0.0",
)
app.include_router(api_router, prefix="/api/v1")
@app.on_event("startup")
async def startup():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
运行方式:
uvicorn app.main:app --reload
启动后访问 http://127.0.0.1:8000/docs 即可看到自动生成的交互式 API 文档。
四、核心差异对比
| 维度 | Flask | FastAPI |
|---|---|---|
| 架构风格 | 微框架,需要自己组装(像搭乐高) | 现代分层架构,类型驱动 |
| 参数校验 | 手动校验,或依赖 flask-wtf 表单 | Pydantic 自动校验,类型即文档 |
| 异步支持 | 原生较弱,需 async 扩展 | 原生 async/await,高并发强 |
| API 文档 | 手写 Swagger,需额外扩展 | 自动生成 Swagger UI + ReDoc |
| 代码组织 | 蓝图 + 应用工厂 | Router + 依赖注入 + 分层 |
| 典型场景 | 传统全栈网站、模板渲染、小型项目 | 纯 API、微服务、AI 工程周边服务 |
五、选型建议
- 项目是前后端不分离的网站(如个人、后台管理系统),需要模板渲染、Session 认证 → 选 Flask
- 项目是前后端分离的纯 API 服务、微服务、对接大模型/AI 应用 → 选 FastAPI,能显著减少“字段随便传、异常随便抛”导致的线上脏数据问题
六、总结
两者并非替代关系:Flask 依然适合快速验证想法和灵活组装,而 FastAPI 代表了新项目在 API 时代的心智转变。
参考链接
- Flask 官方文档:https://flask.palletsprojects.com/
- FastAPI 官方文档:https://fastapi.tiangolo.com/zh/
- SQLAlchemy 文档:https://docs.sqlalchemy.org/

浙公网安备 33010602011771号