Flask、Django、FastAPI:三大 Python Web 框架的底层差异与选型
选框架这件事,在 Python Web 领域几乎每隔几年就要重新讨论一轮。2010 年代 Django 一统天下,2015 年前后 Flask 凭借轻量灵活抢走了大量中小项目的开发者,2018 年 FastAPI 横空出世又在 API 层掀起了新一轮争论。到今天(2026 年 7 月),Django 最新版是 6.0.6,Flask 稳定在 3.1.x 系列,FastAPI 在 0.115+ 上持续演进------三个框架各自的定位和适用场景已经非常清晰了。
但清晰不意味着好选。很多选型讨论停留在"Flask 轻量、Django 全家桶、FastAPI 快"这种标签化的层面,没有触及框架底层的设计哲学差异。这篇笔记从请求处理模型、路由机制、数据验证、ORM、异步支持、部署方式这几个核心维度切入,把三个框架的差异彻底拆开。
一、设计哲学:三个框架解决的根本问题不同
1.1 Django:Web 框架即全家桶
Django 诞生于 2005 年,最初是堪萨斯州《劳伦斯日报》的内部项目。创始人的需求很明确:一个记者要在紧迫的截稿时间内快速做出一个带后台管理的新闻网站。这决定了 Django 从第一天起就不是"微框架"------它的设计目标是把 Web 开发中反复出现的那些东西(ORM、模板引擎、表单处理、用户认证、Admin 后台、CSRF 防护、中间件)全部内置,开发者只需要专注于业务逻辑。
Django 的核心理念是 DRY(Don't Repeat Yourself) 和 "batteries included"。它用的是一个大的、紧密耦合的架构:请求进来后经过 URLconf 路由到 View,View 调用 Model(ORM)读写数据库,再用 Template 渲染 HTML 返回。整个流程被框架严格控制,开发者按照 Django 的约定来写代码。
1.2 Flask:给你一个起点,其余自己选
Flask 的作者 Armin Ronacher(网名 mitsuhiko)在 2010 年创造了这个框架。他的出发点是一个玩笑项目(Werkzeug + Jinja2 的胶水代码),但很快变成了一个有影响力的微框架。
Flask 的核心理念和 Django 完全相反:框架只提供最核心的东西------路由和请求/响应对象------其余所有组件(数据库、表单、认证、Admin)都交给开发者自己选择和组装。你想要 ORM?自己装 SQLAlchemy 或 peewee。你想要表单验证?自己装 WTForms。你想要 Admin 后台?装 Flask-Admin。但这些东西都不是 Flask 的一部分,它们是第三方的 Flask 扩展(Flask Extension)生态。
这种设计的好处是极其灵活------你只需要用到的组件,不用为不需要的功能买单。代价是项目越大,你需要自己做的架构决策越多。10 个人的 Flask 项目和 100 个人的 Flask 项目,往往架构上差异巨大,因为很多在 Django 里开箱即用的东西在 Flask 里需要自己搭。
1.3 FastAPI:类型驱动的高性能 API 框架
FastAPI 由 Sebastián Ramírez 在 2018 年底发布。它的出发点不是替代 Django 或 Flask,而是解决一个具体问题:用 Python 高效地构建 API。FastAPI 不关心 HTML 模板渲染、不关心 Admin 后台、不关心传统的表单处理------它的聚焦点非常窄:接收 JSON 请求、验证数据、调用业务逻辑、返回 JSON 响应,同时提供自动生成的 OpenAPI 文档。
FastAPI 的技术基础是 Starlette(异步 HTTP 框架)和 Pydantic(基于类型注解的数据验证库)。它充分利用了 Python 3.7+ 的 type hints,让数据模型的定义和验证几乎零样板代码。同时,由于 Starlette 底层使用 asyncio,FastAPI 天然支持异步请求处理,在 I/O 密集型场景(大量数据库查询、外部 API 调用)下性能显著优于同步框架。
三个框架的设计哲学差异可以用一句话概括:Django 告诉你"应该怎么做",Flask 告诉你"你随便做",FastAPI 告诉你"用类型注解描述你的接口,剩下的我来"。
二、请求处理模型的底层差异
2.1 WSGI vs ASGI
Django 和 Flask 都是 WSGI 框架。WSGI 最早由 PEP 333 在 2003 年提出(针对 Python 2),后来由 PEP 3333 在 2010 年修订为 WSGI 1.0.1,专门解决了 Python 3 中 bytes 和 str(Unicode)分离的问题。WSGI 的模型是同步的:每个请求进来后,WSGI 应用处理完并返回响应,才能处理下一个请求。这意味着一个长时间运行的请求(比如一个复杂的数据库查询或外部 API 调用)会阻塞整个 worker 进程。
python
# WSGI 应用的标准接口
def application(environ, start_response):
status = '200 OK'
response_headers = [('Content-Type', 'text/plain')]
start_response(status, response_headers)
return [b'Hello World']
Flask 的底层是 Werkzeug(一个 WSGI 工具库),Django 的底层是自己的 WSGI handler。两者都是同步框架。在部署时,你需要在前面放一个 WSGI 服务器(Gunicorn、uWSGI、mod_wsgi),由它管理多个 worker 进程来处理并发。
FastAPI 是 ASGI 框架。ASGI(Asynchronous Server Gateway Interface)是 WSGI 的异步继任者,由 Django 团队的 Andrew Godwin 在 2016 年提出。ASGI 的请求处理模型是基于协程的:
python
# ASGI 应用的标准接口
async def application(scope, receive, send):
await send({'type': 'http.response.start', 'status': 200, 'headers': ...})
await send({'type': 'http.response.body', 'body': b'Hello World'})
当请求处理到某个 await 点(比如等待数据库查询结果),事件循环可以把 CPU 时间片交给其他请求处理。在 I/O 密集型的 API 场景下,一个单进程的 ASGI 服务器可以同时处理成百上千个并发请求,而 WSGI 服务器需要同样数量的 worker 进程才能做到。
2.2 Django 的异步支持现状
Django 从 3.0(2019 年)开始引入异步支持,Django 3.1(2020 年)正式支持异步视图(async def),Django 4.1 和 4.2(2022-2023 年)全面引入了异步 ORM 接口(如 .afirst()、.acount() 以及 async for 迭代)。到 6.0,异步体系已经是相当成熟的基础设施。但需要明确的是:Django 的异步支持是在同步代码库上的渐进式改造,不是从底层重建的。
这意味着 Django 的异步路径有一些限制:
- 中间件(Middleware)仍然默认同步运行,异步中间件的支持是有限的
- 模板引擎(Django Template)是同步的,渲染大模板会阻塞事件循环
- 如果在异步 View 中调用了一个同步的 ORM 方法或第三方库,整个事件循环会被阻塞
在生产环境中,Django 通常搭配 Gunicorn 运行(WSGI 模式),而不是 ASGI 服务器(如 Daphne 或 Uvicorn)。对于传统的"返回 HTML 页面"的场景,WSGI + Gunicorn 已经足够好------瓶颈通常在数据库 I/O,而不是 Python 的请求处理。
2.3 Flask 的异步支持现状
Flask 从 2.0 开始支持异步路由(@app.async_route 或 async def 视图函数),但它的底层仍然是 Werkzeug + WSGI。Flask 使用了 asgiref 库中的 async_to_sync,当检测到视图函数是协程时,会在一个独立线程内运行 asyncio 事件循环来执行它,从而避免阻塞主 WSGI 工作线程。这不是真正的 ASGI------协程最终被塞进了一个同步线程里执行,性能提升有限。
如果你需要一个真正异步的 Flask 生态,可以用 Quart------它是 Flask API 的 ASGI 克隆,但生态和 Flask 不完全兼容。从 3.1 开始 Flask 的维护团队逐步在 ASGI 支持上投入更多资源,但截至 2026 年中期,Flask 仍以同步 WSGI 为主流部署方式。
2.4 FastAPI 的异步是原生的
FastAPI 从第一天起就是 ASGI 框架。底层 Starlette 是一个完整的 ASGI toolkit,请求/响应对象、路由、中间件、WebSocket、后台任务------全部是 async/await 原生实现的。Pydantic v2 的核心也是用 Rust 编写的(pydantic-core),数据验证的性能比纯 Python 实现快了 5-50 倍。
FastAPI 通常搭配 Uvicorn(ASGI 服务器)运行:
bash
uvicorn main:app --workers 4 --host 0.0.0.0 --port 8000
在 I/O 密集型的 JSON API 场景下,FastAPI + Uvicorn 的性能确实显著优于 Flask + Gunicorn 或 Django + Gunicorn。TechEmpower 的基准测试中,FastAPI 在简单的 JSON 序列化场景下可以达到 Node.js 和 Go 框架的同一量级。但需要指出的是:这种性能优势主要体现在请求处理层面(解析请求、验证数据、序列化响应),如果瓶颈在数据库查询或外部 API 调用上,FastAPI 的异步优势需要配合异步数据库驱动(如 asyncpg、databases、SQLAlchemy 的 async session)才能充分发挥。
三、路由与 URL 分发
3.1 Django 的 URLconf
Django 用一个独立的 Python 模块(urls.py)来做 URL 路由,基于正则表达式:
python
# urls.py
from django.urls import path, re_path
from . import views
urlpatterns = [
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
re_path(r'^articles/(?P<slug>[\w-]+)/$', views.article_detail),
]
path() 提供了简洁的路径语法(<int:year>),re_path() 支持完整的正则表达式。path() 和与之配套的 register_converter 是 Django 2.0(2017 年 12 月发布)引入的核心特性,允许自定义路径参数类型。
Django 的 URL 配置支持层级化分解 ------每个子应用可以有自己独立的 urls.py,主 urls.py 通过 include() 把子路由挂载进来:
python
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls')),
path('api/', include('api.urls')),
]
这在大型项目里非常实用,团队可以独立管理各自模块的路由。
3.2 Flask 的路由装饰器
Flask 用装饰器来做路由,直接写在视图函数上:
python
@app.route('/articles/<int:year>/')
def year_archive(year):
...
@app.route('/articles/<int:year>/<int:month>/')
def month_archive(year, month):
...
路由定义和视图函数是紧耦合的,这意味着你不能在不修改视图函数代码的情况下改变路由路径(除非使用 Flask 的 Blueprint 来做模块化分解)。Blueprint 是 Flask 的应用模块化机制,可以把一组路由和视图打包成可复用的组件:
python
from flask import Blueprint
blog = Blueprint('blog', __name__)
@blog.route('/articles/<int:year>/')
def year_archive(year):
...
# 在主应用里注册
app.register_blueprint(blog, url_prefix='/blog')
Blueprint 在逻辑上等价于 Django 的 include(),但需要更多的手动组织。
3.3 FastAPI 的路径装饰器 + 类型驱动
FastAPI 的路由定义方式和 Flask 类似(装饰器 + 路径参数),但数据验证完全由类型注解驱动:
python
from fastapi import FastAPI, Path
from typing import Optional
app = FastAPI()
@app.get('/articles/{year}/{month}')
async def month_archive(
year: int,
month: int,
q: Optional[str] = None, # 查询参数,可选
page: int = 1, # 查询参数,默认值
):
...
路径参数、查询参数、请求体的类型和约束都通过 Python 类型注解声明,FastAPI 自动完成验证和错误处理。如果一个客户端传了 year=abc,FastAPI 会返回一个格式规范的 422 错误响应,不需要你写任何验证代码。Django 和 Flask 里你需要手动调用 request.args.get() 并做类型转换和错误处理。
FastAPI 还支持路由分组(APIRouter),功能和 Flask 的 Blueprint 类似,但额外支持 OpenAPI 标签和依赖注入:
python
from fastapi import APIRouter
router = APIRouter(prefix='/articles', tags=['articles'])
@router.get('/{year}')
async def year_archive(year: int):
...
四、数据验证与请求处理
4.1 Django 的 Form 和 ModelForm
Django 提供了一套完整的表单处理系统。Form 类处理任意数据的验证,ModelForm 自动根据 Model 生成表单字段:
python
# forms.py
from django import forms
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'content', 'published']
widgets = {
'content': forms.Textarea(attrs={'class': 'richtext'}),
}
def clean_title(self):
title = self.cleaned_data['title']
if len(title) < 5:
raise forms.ValidationError('标题至少 5 个字符')
return title
验证逻辑写在 clean_* 方法里,错误信息通过 errors 字典传递。这套系统为 HTML 表单设计,处理的是 application/x-www-form-urlencoded 和 multipart/form-data 格式的数据。如果用来处理 JSON API 的请求体,需要手动从 request.body 中解析 JSON 并构造表单数据,用起来不够自然。
4.2 Flask 的手动验证
Flask 没有内置的表单验证系统。最常见的方式是用 WTForms 扩展:
python
from flask import request
from wtforms import Form, StringField, IntegerField, validators
class ArticleForm(Form):
title = StringField('标题', [validators.Length(min=5)])
content = StringField('内容', [validators.DataRequired()])
@app.route('/articles', methods=['POST'])
def create_article():
form = ArticleForm(request.form)
if not form.validate():
return {'errors': form.errors}, 400
# ...
对于 JSON API,你需要从 request.get_json() 中取出数据,手动传入 WTForms 或自己写验证逻辑。Flask 3.1 引入了对 Pydantic 的有限集成(通过 flask-pydantic 扩展),但不是内置功能。
4.3 FastAPI 的 Pydantic 模型验证
FastAPI 的数据验证是它最大的卖点之一。Pydantic v2 用 Python 类型注解定义数据模型,验证在请求进入业务逻辑之前自动完成:
python
from pydantic import BaseModel, Field, EmailStr
from datetime import datetime
class ArticleCreate(BaseModel):
title: str = Field(min_length=5, max_length=200)
content: str = Field(min_length=1)
author_email: EmailStr
published: bool = False
tags: list[str] = Field(default_factory=list)
@app.post('/articles')
async def create_article(article: ArticleCreate):
# article 已经是一个经过验证的 Python 对象
# 如果请求体不符合模型定义,FastAPI 自动返回 422
...
Pydantic v2 的底层(pydantic-core)是用 Rust 实现的,验证速度极快。对比 Django Form 和 WTForms,Pydantic 有几个显著优势:
- 原生支持复杂嵌套结构 :
list[ArticleCreate]、dict[str, User]等嵌套类型可以直接声明 - JSON 序列化/反序列化一体化 :同一个模型既能解析请求体,又能序列化响应(
model.model_dump()) - 自动生成 JSON Schema:每个 Pydantic 模型自动导出 JSON Schema,FastAPI 据此生成 OpenAPI 文档
五、ORM 与数据库交互
5.1 Django ORM:框架内置、深度集成
Django 自带 ORM,这是它和 Flask、FastAPI 最大的架构差异之一。Django ORM 和框架的其他组件(Admin、ModelForm、信号系统、序列化器)深度集成,你定义一个 Model,Admin 后台自动就有了增删改查界面,ModelForm 自动有了对应的字段。
python
# models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['title', 'published']),
]
Django ORM 的优点是与框架的高度一致性 ------迁移用 makemigrations + migrate,查询用 Article.objects.filter(published=True),链式调用返回新的 QuerySet 而不是修改原始对象。缺点是它的 API 风格和 SQLAlchemy 完全不同,学习成本互不通用;在复杂查询(多表 JOIN、子查询、窗口函数)上,Django ORM 的表达能力不如原始 SQL 或 SQLAlchemy Core。
Django 6.0 开始支持异步 ORM 查询:
python
async def get_articles():
articles = await Article.objects.filter(published=True).afirst()
# 或异步迭代
async for article in Article.objects.all():
...
但如前所述,异步 ORM 在 Django 中的使用场景仍然有限,大部分生产环境仍然使用同步方式。
5.2 Flask:ORM 自由选择
Flask 不带 ORM。最常见的选择是 SQLAlchemy(通过 Flask-SQLAlchemy 扩展):
python
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
class Article(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
content = db.Column(db.Text)
published = db.Column(db.Boolean, default=False)
你也可以选择其他方案:peewee(更轻量的 ORM)、Tortoise ORM(异步 ORM,配合 FastAPI 更常见)、或者直接用 asyncpg / aiomysql 写原始 SQL。Flask 的哲学是:数据库层不是框架的一部分,你自己决定。
5.3 FastAPI:与 ORM 无耦合,异步驱动是主流
FastAPI 同样不内置 ORM。社区最常见的搭配有几种:
- SQLAlchemy(异步模式) :
AsyncSession+ async engine,适合复杂的关系型数据库操作 - Tortoise ORM:原生 asyncio ORM,API 风格接近 Django ORM,在 FastAPI 社区中非常流行
- SQLModel:FastAPI 作者自己写的库,把 SQLAlchemy Model 和 Pydantic Model 合二为一
- 纯数据库驱动 :
asyncpg(PostgreSQL)、aiomysql(MySQL),用原始 SQL
python
# SQLModel 的例子(SQLAlchemy + Pydantic 融合)
from sqlmodel import SQLModel, Field, Session, select
class Article(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
title: str = Field(max_length=200)
content: str
published: bool = False
@app.get('/articles/{article_id}')
async def get_article(article_id: int, session: AsyncSession = Depends(get_session)):
result = await session.execute(select(Article).where(Article.id == article_id))
return result.scalar_one_or_none()
SQLModel 的设计思路是:一个类既是 Pydantic 模型(用于请求/响应验证),又是 SQLAlchemy 模型(用于数据库映射),避免了在两个模型类之间做数据转换的样板代码。
六、模板渲染 vs API 返回
6.1 Django Template Engine
Django 内置了模板引擎,直接在服务器端渲染 HTML:
html
<!-- article_list.html -->
{% extends "base.html" %}
{% block content %}
<h1>文章列表</h1>
{% for article in articles %}
<div class="article">
<h2>{{ article.title }}</h2>
<p>{{ article.content|truncatewords:50 }}</p>
<time>{{ article.created_at|date:"Y-m-d" }}</time>
</div>
{% empty %}
<p>暂无文章</p>
{% endfor %}
{% endblock %}
Django 模板引擎的设计哲学是安全优先:默认转义所有变量输出(防止 XSS),模板里不能直接调用任意 Python 函数(必须通过 filter 或 tag)。这种限制让前端团队(不一定是 Python 开发者)也能安全地修改模板。
6.2 Flask + Jinja2
Flask 默认使用 Jinja2,和 Django Template 语法相似但功能更灵活。Jinja2 支持在模板里做更多运算(循环、条件、宏定义),但同样默认转义变量输出。和 Django 不同的是,Flask 和 Jinja2 可以轻松替换------你可以切换到其他模板引擎(如 Mako、Chameleon),或者完全不用模板引擎(纯 API 项目)。
6.3 FastAPI:不关心模板
FastAPI 没有内置模板引擎。如果你需要返回 HTML(比如服务端渲染的页面),需要自己安装 Jinja2 或其他模板引擎,手动集成。这在 FastAPI 的定位里是合理的------FastAPI 的核心场景是 API,不是 HTML 页面。如果你需要模板渲染,Django 或 Flask 是更合适的选择。
七、中间件与请求生命周期
7.1 Django 中间件
Django 的中间件系统是一个洋葱模型------请求从外层中间件进入,穿过所有中间件到达 View,响应从 View 出来再从内到外穿过所有中间件返回。
python
class RequestTimingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start = time.time()
response = self.get_response(request)
duration = time.time() - start
response['X-Response-Time'] = f'{duration:.3f}s'
return response
Django 内置了大量中间件:SecurityMiddleware(HTTPS 重定向、HSTS)、SessionMiddleware(会话管理)、AuthenticationMiddleware(用户认证)、CsrfViewMiddleware(CSRF 防护)、CommonMiddleware(URL 规范化)。这些中间件在 settings.MIDDLEWARE 里配置,执行顺序由列表顺序决定。
7.2 Flask 的 before/after 请求钩子
Flask 的中间件等价物是 @app.before_request、@app.after_request 和 @app.teardown_request 装饰器:
python
@app.before_request
def set_request_id():
g.request_id = str(uuid4())
@app.after_request
def add_timing_header(response):
response.headers['X-Request-ID'] = g.request_id
return response
这种设计比 Django 的中间件简单得多,没有洋葱模型的概念------before_request 按注册顺序执行,after_request 按注册的逆序执行。对于大多数场景够用,但如果需要复杂的请求/响应链式处理,Flask 的钩子不如 Django 的中间件灵活。
7.3 FastAPI 的 ASGI 中间件
FastAPI 使用 Starlette 的 ASGI 中间件,底层是纯 async/await:
python
from starlette.middleware.base import BaseHTTPMiddleware
class TimingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
start = time.time()
response = await call_next(request)
response.headers['X-Response-Time'] = f'{time.time() - start:.3f}s'
return response
ASGI 中间件可以拦截 WebSocket 连接和 HTTP 请求,比 WSGI 中间件的应用范围更广。FastAPI 内置了 CORS、GZip、HTTPS redirect 等常用中间件,直接通过参数配置即可。
八、认证与权限
8.1 Django:开箱即用
Django 内置了完整的认证系统------django.contrib.auth。用户模型、权限系统、Group、Session 管理、密码哈希(PBKDF2/Argon2)、装饰器(@login_required、@permission_required)全部内置。Django 6.0 还支持了 WebAuthn(无密码认证)。
对于 API 场景,Django REST Framework(DRF)提供了 Token 认证、JWT 认证、OAuth2 等方案。DRF 是一个独立的第三方库,但和 Django 的集成度极高,几乎被视为 Django 生态的标准 API 层。
8.2 Flask:自己组装
Flask 没有内置认证系统。常见方案是 Flask-Login(Session 认证)、Flask-JWT-Extended(JWT 认证)、Flask-OAuthlib(OAuth)。需要开发者自己选择、配置、组装。
8.3 FastAPI:OAuth2 + JWT 原生支持
FastAPI 内置了对 OAuth2 密码流和 JWT 的支持,通过 fastapi.security 模块:
python
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get('/me')
async def get_me(token: str = Depends(oauth2_scheme)):
user = decode_token(token)
return user
OpenAPI 文档(Swagger UI)会自动出现一个"Authorize"按钮,前端开发者可以直接在文档页面上测试认证流程。这是 FastAPI 在 API 开发体验上的一个显著优势。
九、文档生成
9.1 Django:无内置 API 文档
Django 本身不生成 API 文档。DRF 提供了一个可浏览的 API 界面(Browsable API),但它不是 OpenAPI 文档。如果需要 Swagger 文档,需要额外安装 drf-spectacular 或 drf-yasg。
9.2 Flask:无内置 API 文档
Flask 同样没有内置 API 文档能力。需要用 flask-smorest(基于 marshmallow)、flask-openapi3 或 apispec 等第三方扩展来生成。
9.3 FastAPI:自动生成 OpenAPI 文档
FastAPI 的 OpenAPI 文档是开箱即用的。只要你定义了路由和类型注解,FastAPI 自动生成:
- Swagger UI :访问
/docs,交互式的 API 文档页面,支持在线测试 - ReDoc :访问
/redoc,更美观的文档阅读页面 - OpenAPI JSON Schema :访问
/openapi.json,可用于代码生成(前端 SDK、客户端库)
这是 FastAPI 区别于 Django 和 Flask的最显著特性之一。对于前后端分离的项目,API 文档的自动生成可以大幅降低前后端的沟通成本。Django + DRF 也能做到,但需要额外安装和配置至少一个扩展。
十、部署与运维
10.1 部署方式对比
| 维度 | Django | Flask | FastAPI |
|---|---|---|---|
| 服务器 | Gunicorn(WSGI) | Gunicorn(WSGI) | Uvicorn(ASGI) |
| 进程模型 | 多 worker 同步 | 多 worker 同步 | 异步 + 多 worker |
| 生产推荐 | Gunicorn + Nginx | Gunicorn + Nginx | Uvicorn + Nginx |
| Docker 化 | 标准做法,Django 官方有镜像 | 标准做法 | 标准做法 |
| 静态文件 | collectstatic + WhiteNoise |
Flask 内置或 Nginx 代理 | Nginx 代理(API 通常不涉及) |
10.2 Django 的 manage.py 工具链
Django 提供了 manage.py 作为项目管理的统一入口:
bash
python manage.py runserver # 开发服务器
python manage.py migrate # 数据库迁移
python manage.py makemigrations # 生成迁移文件
python manage.py createsuperuser # 创建管理员
python manage.py shell # Django 增强版 shell
python manage.py test # 运行测试
python manage.py collectstatic # 收集静态文件
python manage.py check --deploy # 部署前检查
这套工具链在大型团队协作中非常实用,但学习成本也更高------新成员需要理解 Django 的项目结构、settings 分层、migration 机制等概念。
10.3 Flask 的轻量部署
Flask 的部署极简。一个最小的 Flask 应用只需要一个 Python 文件:
python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello World'
flask run 直接启动开发服务器,gunicorn app:app 直接启动生产服务器。没有 manage.py,没有迁移系统(除非你用了 Flask-Migrate),没有 collectstatic。这种极简在小型项目和微服务里是优势,但在大型项目里会变成负担------你需要自己搭建这些基础设施。
10.4 FastAPI 的容器化部署
FastAPI 通常部署为容器化的 API 服务:
dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "main:app", "-k", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000", "--workers", "4"]
这里用 Gunicorn 作为主进程管理器,搭配 UvicornWorker 作为 worker 类。Gunicorn 在进程管理(master-worker 架构、worker 崩溃自动重启、graceful reload、僵尸进程回收)方面比单独使用 Uvicorn 的 --workers 更成熟稳健,是 FastAPI 官方文档推荐的生产部署方式之一。开发时可以继续用 uvicorn main:app --reload 快速迭代。
十一、性能基准测试的客观解读
经常看到"FastAPI 性能是 Flask 的 2-3 倍"这种说法。这个数字在纯 JSON API 的简单场景下大致成立,但需要注意前提条件:
- 测试内容:通常是"接收一个 JSON 请求体,验证数据,返回一个 JSON 响应",没有数据库查询、没有业务逻辑
- FastAPI 的优势来源:Pydantic v2 的 Rust 序列化/反序列化 + Starlette 的异步请求处理
- Flask/Django 的劣势来源:同步 WSGI 模型 + 纯 Python 的数据解析
一旦引入数据库查询(尤其是多次查询),瓶颈就从"请求处理"转移到了"I/O 等待"。此时 FastAPI 的异步优势取决于数据库驱动是否也是异步的。如果你用同步的 psycopg2 而不是异步的 asyncpg,FastAPI 的性能优势会被严重削弱。
对于大多数实际项目来说,框架性能不是选型的决定性因素。数据库优化、缓存策略、网络架构的影响远比框架本身的请求处理速度大。真正影响选型的是开发效率、团队技能、项目复杂度和维护成本。
十二、选型决策
12.1 选型速查
| 项目特征 | 推荐框架 | 原因 |
|---|---|---|
| 内容型网站(博客、CMS、新闻) | Django | ORM + Admin + 模板引擎一站式解决 |
| 企业管理后台(CRM、ERP) | Django | Admin 后台 + 权限系统 + Form 开箱即用 |
| 纯 JSON API / 微服务 | FastAPI | 类型验证 + 异步 + 自动文档,开发效率高 |
| AI/ML 模型服务 | FastAPI | Pydantic 的数据验证天然适合模型输入输出 |
| 小型项目 / 原型 | Flask | 上手最快,灵活度最高 |
| 需要高度定制的 Web 应用 | Flask | 不被框架约束,自由选择组件 |
| 大团队标准化项目 | Django | 约定优于配置,团队协作效率高 |
12.2 一个容易忽视的选项:混搭
三个框架不是互斥的。在微服务架构中,完全可以同时使用 Django(内容管理后台)和 FastAPI(API 网关 / 模型服务)。Django REST Framework 也经常和 FastAPI 共存于同一项目中------Django 处理需要 ORM 的数据密集型逻辑,FastAPI 处理需要高性能的 API 端点。
选框架之前,先想清楚你要解决的问题是什么,而不是"哪个框架更流行"。