ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

后端框架选型对比:Django、Flask、FastAPI从定位到实战取舍

后端框架选型对比:Django、Flask、FastAPI从定位到实战取舍

后端选型这件事,我一开始真没当回事。Django、Flask、FastAPI 这几个框架,在我最初看来不过是 Python 写 Web 服务的不同姿势而已,能有多大差别?后来自己亲手带过几个风格迥异的项目,才慢慢明白:选错框架不是写不出功能,而是会在某个节点集中爆发改造成本。比如在某内部管理项目里用 Django 做得飞快,结果后面要加实时推送通道时就挠头;又在一个纯 API 服务里图省事用了 Flask,结果路由和数据校验全靠手写,维护到后期到处都是自定义装饰器。这篇对比我不会只给你列性能数字,而是把三个框架的定位、底层并发模型、数据层设计、部署运维习惯,以及我真实项目里踩过的坑都摊开来聊,给正在纠结选型的你一个可执行的参照。

1. 先分清定位:三种框架的适用边界

很多人一上来就比语法比性能,但我觉得第一件事应该是看定位。这三个框架出生年代不同、设计哲学不同,面向的场景也不同,搞不清这个,后面所有对比都是空中楼阁。

1.1 Django:全家桶式的厚重路线

Django 的核心理念是“batteries included”,翻译过来就是“能给你备齐的都给你备齐”。它内置了 ORM、Admin 后台、认证系统、表单处理、模板引擎、迁移工具、中间件机制,甚至还有自定义命令。很多刚接触 Django 的人会被它的目录结构和配置吓到,但一旦跑通,你就会发现它能帮你省掉大量基础代码。一个常规的增删改查后台系统,Django 的开发速度在三个框架里是当之无愧的第一。它的适用场景很明确:内部管理系统、CMS、OA、带复杂表单的业务系统,以及团队需要统一规范、快速交付的项目。

但“厚重”的另一面是“笨重”。Django 的约定非常强,你很难脱离它那一套体系去自由发挥。例如你想换掉默认的 User 模型,或者在 ORM 层做非常底层的优化,就会感觉全身被束缚。它还自带中间件链和全局状态,请求经过的每一层都有成本。很多人骂 Django 慢,其实不是框架本身不可接受,而是你拿它去和纯 API 框架比性能,本身就不公平。它的慢主要来自同步 WSGI 模式加全功能装载,如果你只是做一个内部业务系统,一天几百个并发用户,这个“慢”几乎无感。

1.2 Flask:轻量灵活的自由主义

Flask 的定位是“微框架”,核心只有路由、request/response、session 和调试服务器。你几乎可以从一个文件开始写代码,也可以灵活扩展到大规模项目。数据库用什么?你自己选。校验怎么搞?你自己配。模板引擎默认用 Jinja2,但换个别的也不是不行。这种“把选择权交给开发者”的设计,让 Flask 在中小型项目、API 原型、嵌入式服务、内部工具里非常受欢迎。比如我做一些一次性数据展示页、运维平台的小模块,用 Flask 简直是十分钟上线。

自由的代价是要求开发者自己有架构能力。Flask 项目初期很爽,但如果没人约束,很容易从几个路由膨胀成一堆散落的函数,最后变成一个“大泥球”。蓝图(Blueprint)确实能帮你按模块拆分,但拆分到什么粒度、依赖怎么管理、校验和序列化放在哪一层,框架统统不管。也就是说,用 Flask 做三五个月内能交付的项目很合适,但做一个生命周期很长的核心业务系统,需要团队有很强的工程纪律。

1.3 FastAPI:性能驱动的现代路线

FastAPI 是三个里最年轻的,特点是“类型提示驱动”。你可以用 Python 的类型注解直接定义请求参数和响应模型,框架会自动帮你完成校验、序列化,甚至自动生成 OpenAPI 文档。它跑在 ASGI 协议上,原生支持 async/await,所以面对高并发 I/O 场景、长连接、WebSocket、SSE 这类需求时,天然比前两个框架有力。性能方面,纯接口压测下 FastAPI 通常会大幅领先 Flask 和 Django,在一些简单场景里甚至能逼近 Node.js 和 Go,这也是它这几年热度冲得快的主要原因。

但它不是万能的。FastAPI 没有内置 Admin,没有像 Django 那样完整的后台管理生态,模板渲染和传统服务端页面也不是它的重点。如果一个项目核心目标是做一套服务端渲染的复杂后台,用 FastAPI 就得自己拼很多东西,反而不如 Django 顺手。更关键的是,异步编程是有心智负担的,团队如果没有 async/await 的经验,乱用 async 反而会把性能搞崩。后面我会专门讲这个坑。

所以定位先记在心里:Django 适合业务后台、Flask 适合轻量灵活服务、FastAPI 适合 API 和高并发场景。三者不是谁取代谁,而是面向不同战场。

2. 核心机制横向拆解:同步异步、数据层、生态差异

定位清楚了,接下来得看底层机制。三个框架最大的分水岭其实就是同步与异步,这个差异会决定你的接口并发能力,也会影响你对数据库、缓存、消息队列等组件的使用方式。

2.1 WSGI 与 ASGI:并发模型差异到底影响什么

Django 和 Flask 本质上是基于 WSGI 协议的,FastAPI 则完全跑在 ASGI 协议上。想理解性能差异,得先明白这两个协议背后并发模型的不同。

WSGI 是同步网关接口,每个请求进来,通常由一个线程或进程去处理。处理过程中如果遇到数据库查询、外部 API 调用这类 I/O 等待,这个线程就卡在那里了。虽然我们可以通过多线程、多进程来提升并发,但线程多了内存占用高,线程切换也有开销。而且 Python 还有 GIL 的限制,纯 CPU 计算并不能靠多线程加速。所以基于 WSGI 的框架,在高并发 I/O 场景下很容易出现“请求能进来,但都在排队等线程”的情况。

ASGI 是异步网关接口,核心是事件循环。一个事件循环进程可以同时管理成千上万个连接,遇到 I/O 等待时就切去执行其他协程任务,因此单进程也能处理大量长连接和并发请求。生活里类比就是:WSGI 服务员为一桌客人点菜,上菜前只能干等着;ASGI 服务员可以给 A 桌点完菜后,马上去给 B 桌加水,等 A 桌的菜好了再端过去。这种调度方式,让单进程的吞吐量大很多。

FastAPI 里同时支持async def和普通def,很多人会忽略它们背后的区别。async def会被放在事件循环里直接执行,如果函数内部出现了同步阻塞调用,比如requests.get()、time.sleep()或者同步方式查 MySQL,整个事件循环都会被卡住,其他请求全得排队,性能反而暴跌。普通def则会被 FastAPI 自动放到线程池里执行,虽然不如纯协程那么轻量,但至少不会阻塞主循环。我的建议是:视图函数里如果有同步库调用,就老老实实写普通def;如果要发挥异步优势,请用httpx.AsyncClient、异步驱动这类配套方案。

网上很多 benchmark 里,FastAPI 的 QPS 比 Flask、Django 高不少,但实际开发中差异往往没有数字那么大,因为真实瓶颈通常在下游:数据库查询慢、N+1 问题严重、第三方接口响应慢、序列化逻辑重。这些在任何框架里都一样。所以你可以把“FastAPI 性能好”理解成它给了一个更好的并发底座,但能不能发挥出来,还要看整个调用链是不是真异步化。

2.2 数据层对比:ORM、序列化与校验方式的分野

数据层是三个框架差异最明显的地方。Django 自有一套完整的 ORM,模型定义、字段类型、迁移、关系查询都集成得很好,配合它的 Admin 和 Form 体系,业务数据管理非常顺滑。尤其是select_related、prefetch_related这些查询优化手段,内置得很自然,新手上手很快。缺点是这套 ORM 对复杂 SQL 的表达有限,遇到多表嵌套的报表统计,经常要写原生 SQL 或.extra(),体验就比较拧巴。

Flask 没有官方 ORM,社区事实标准是 SQLAlchemy。SQLAlchemy 比 Django ORM 更底层、更灵活,既能用 ORM 方式操作数据,也能保留原生 SQL 的空间。Flask 项目里通常还要搭配 Flask-Migrate 做迁移,本质是封装了 Alembic。序列化和校验则比较随性,可以用 Marshmallow、Pydantic,也可以手写 dict,框架不干预。好处是自由,坏处是不同开发者写出来的风格可能千差万别。我见过同一个 Flask 项目里两种校验风格并存的,维护成本很高。

FastAPI 的推荐做法是用 SQLAlchemy 或 SQLModel 管理数据库模型,用 Pydantic 定义请求和响应模型。一个关键区别是:FastAPI 里“数据模型”和“接口模型”往往是分开的。ORM 模型负责存取数据库,Pydantic 模型负责对外接收和返回数据,两者之间自己做转换。这个分离一开始会觉得繁琐,但项目大了以后非常舒服,因为接口层完全可控,不会不小心把密码哈希、内部字段暴露出去。Pydantic 还依托类型提示做校验,写起来像定义普通 Python 类,却能自动生成错误信息、过滤多余字段,并联动 OpenAPI 文档。

数据校验方式也值得对比一下:Django 用 ModelForm 或 DRF Serializer 解决,Flask 通常靠 Marshmallow/手写校验,FastAPI 靠 Pydantic 类型体系。前者“约定感”强,中间者“自由度高”,后者“类型感”强。对我来说,如果这是一个重表单、需要文件上传、需要和页面模板深度绑定的业务系统,Django 的数据层体验最好;如果是纯 JSON API,Pydantic 的爽感非常直观。

维度DjangoFlaskFastAPI
内置 Admin有,开箱即用无,需第三方扩展无,需自己实现
ORM内置 Django ORM常用 SQLAlchemy常用 SQLAlchemy / SQLModel
迁移工具内置 makemigrationsAlembic / Flask-MigrateAlembic
请求校验Forms / DRF SerializerMarshmallow / 手写Pydantic
异步支持官方还偏同步偏同步原生异步
API 文档DRF 可集成需配置 apispec / flasgger自动生成 OpenAPI
社区成熟度非常成熟非常成熟快速上升

2.3 周边生态与社区成熟度:工具箱决定交付速度

一个框架的生态,决定了你遇到问题时是“搜一下就有现成方案”还是“自己造轮子”。Django 在这方面是王者。官方就包含 CSRF 防护、XSS 转义、认证、密码哈希、分页、日志等,第三方包更是覆盖支付、导入导出、权限控制、后台美化,基本上你能想到的业务组件都有直接能用的方案。对于时间紧、预算有限的传统项目,Django 生态是一种确定性。

Flask 的生态特征是“碎片化组合”。它有很多扩展,质量参差不齐,同一个功能可能有好几个流行库,比如用户认证有 Flask-Login、Flask-JWT-Extended、Flask-Security 可选。选型时你需要自己做技术判断,否则很容易陷入“扩展依赖版本互相打架”的泥潭。但它的优势也在这里:你能按需组装出一个贴合业务的最小系统,不会像 Django 那样开场就带一堆东西。

FastAPI 周边生态还在快速成型中,但关键组件已经很能打了。Pydantic 是最核心的一环,配套的SQLModel、pydantic-settings、fastapi-cache、fastapi-pagination等库都很活跃。异步测试有httpx和pytest-asyncio,部署有uvicorn。如果你只做 API,FastAPI 的生态其实是够用的,甚至因为文档自动生成,前后端联调效率会高出不少。但如果哪天你想找一个现成的“扁平化后台管理界面”,可能得失望了,这块还是 Django 的舒适区。

生态成熟度还有一个隐藏价值:招聘和学习资料。Django 人口基数大,面试者普遍会;Flask 语法简单,上手也很快;FastAPI 虽然热度高,但从业者里真正把异步玩明白的人并不多。这会影响你团队的招聘和培训成本,选型时别忽略。

3. 同一业务三套实现:代码层面的直观对比

原理讲再多,不如直接上代码体验感强。这一节我用一个最小示例和一个用户注册接口,带你看三套框架在代码思维上的差异。

3.1 三套最小可运行示例的生命周期差异

Django 创建项目时,你首先感受到的是“正式感”。需要先django-admin startproject创建项目,再startapp创建应用,然后去settings.py注册应用、配置数据库,最后到urls.py里挂路由。甚至一个最简单的页面,你都要在views.py里写一个函数,再配一个 URL。这不是坏事,它逼着你按约定组织代码,但初次接触的人确实会觉得步骤烦琐。

django-admin startproject myproject cd myproject python manage.py startapp myapp python manage.py runserver

Flask 的最小示例就是一个普通 Python 脚本,甚至不需要专门的命令行工具:

from flask import Flask app = Flask(__name__) @app.get("/") def index(): return {"message": "hello world"} if __name__ == "__main__": app.run()

FastAPI 也差不多,但启动方式变成了 ASGI 服务器:

from fastapi import FastAPI app = FastAPI() @app.get("/") def index(): return {"message": "hello world"}

启动时用uvicorn main:app --reload。你会发现 Flask 和 FastAPI 的代码量看起来差不多,但生命周期不同:FastAPI 在应用启动时会扫描所有路由装饰器,收集类型信息,生成 OpenAPI schema;Flask 则按需注册路由,启动代价更小。Django 启动时要做的事情最多,它会初始化 settings、建立应用注册表、检查迁移,所以你比较少看到有人用 Django 做一个极轻量的小服务。

3.2 用户注册接口:一种业务,三种思维模式

下面这个注册接口只展示了核心逻辑,省略了密码哈希、事务处理等细节,重点看数据校验流程。

Django 加 DRF 的写法,把校验集中在一块:

# serializers.py from rest_framework import serializers from .models import User class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ["username", "email", "password"] def validate_password(self, value): if len(value) < 8: raise serializers.ValidationError("密码至少 8 位") return value
# views.py from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .serializers import UserSerializer class RegisterView(APIView): def post(self, request): serializer = UserSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Flask 加 Marshmallow 的写法,解析和校验在 Schema 里做:

from flask import Flask, request, jsonify from marshmallow import Schema, fields, validate, ValidationError app = Flask(__name__) class RegisterSchema(Schema): username = fields.Str(required=True, validate=validate.Length(min=3)) email = fields.Email(required=True) password = fields.Str(required=True, validate=validate.Length(min=8)) schema = RegisterSchema() @app.post("/register") def register(): try: data = schema.load(request.get_json()) except ValidationError as e: return jsonify(e.messages), 400 # 这里再去创建用户 return jsonify({"username": data["username"], "email": data["email"]}), 201

FastAPI 的写法,校验直接放在类型注解里:

from fastapi import FastAPI from pydantic import BaseModel, EmailStr, Field app = FastAPI() class RegisterRequest(BaseModel): username: str = Field(min_length=3) email: EmailStr password: str = Field(min_length=8) @app.post("/register") def register(data: RegisterRequest): # data 已经通过校验,直接使用 return {"username": data.username, "email": data.email}

三种方案的结果都是把校验逻辑和业务逻辑分开,但思维模式明显不同。DRF 是“框架帮你定义好 serializer 的写法”,Marshmallow 是“独立的序列化库和你手里的 request 融合”,Pydantic 则是“类型即校验、类型即文档”。如果你经历过纯手写if not request.json.get("username")的时期,可能会很享受 FastAPI 这种“零模板校验”的感觉;而如果你更看重业务后台里复杂字段的联动校验,Django 的 Form/Serializer 体系会更全面。

3.3 中间件、依赖注入与路由设计的区别

很多项目做大了,头疼的往往不是接口逻辑,而是横切关注点:用户认证、权限校验、请求日志、事务边界、参数注入。三个框架对这一块的处理思路也不同。

Django 中间件类是独立的,它在请求进入视图之前和响应返回之后各执行一段逻辑,同时还能读取全局 request。Flask 则是通过before_request、after_request装饰器和全局对象g来实现类似能力,配合蓝图为不同模块挂不同逻辑。FastAPI 的方式更现代,它既支持 ASGI 中间件,也支持基于类型标注的依赖注入(Depends)。依赖注入是 FastAPI 非常有特色的设计,例如在视图里声明一个参数user: User = Depends(get_current_user),FastAPI 会在进入视图前自动调用get_current_user完成鉴权,并把结果传进来。多个依赖可以嵌套、组合、复用,写出来的代码很规整。

Flask 和 Django 也能做到类似的事,但通常要靠装饰器包装或在中间件里写一堆判断。小项目无所谓,一旦认证逻辑、权限判断、租户隔离混在一起,装饰器式的写法很容易出现“顺序不对”“忘了加装饰器”这类问题。FastAPI 的依赖注入则把依赖关系显式画了出来,测试时还能很方便地覆盖依赖。这是我个人认为 FastAPI 在现代 API 项目里最值得尝试的理由。

路由设计上,Django 用集中式urls.py层层包含,Flask 用蓝图,FastAPI 用APIRouter。三者都能实现模块化,差别不大。但 FastAPI 的路径参数、查询参数、请求体会直接通过类型系统绑定,配合自动文档,前端同事拿到 Swagger UI 基本就可以自测接口了,联调沟通成本会低一截。

4. 部署、测试与运维:工程化的对照

写框架只是第一步,真正决定项目长期体验的是部署、测试和运维。这三个框架在这方面的成熟度不太一样,得分开看。

4.1 部署形态:WSGI 与 ASGI 下的服务配置

Django 和 Flask 传统的部署方式都是用 WSGI 服务器,最常见的就是 gunicorn。命令大概是这样的:

# Django gunicorn -w 4 -b 0.0.0.0:8000 myproject.wsgi:application # Flask gunicorn -w 4 -b 0.0.0.0:5000 app:app

生产环境里不要用runserver或flask run,那都是开发服务器,性能和安全性都不达标。Django 还要处理静态文件收集、CSRF、HTTPS 转发等配置,Flask 的静态文件服务也更适合交给 Nginx。

FastAPI 的正常开发启动是uvicorn main:app --reload,但生产环境单进程跑 uvicorn 并不是最好的方案,通常会用 gunicorn 启动一个兼容 ASGI 的 worker:

gunicorn -k uvicorn.workers.UvicornWorker -w 4 app:app

这里的-k uvicorn.workers.UvicornWorker是让 gunicorn 作为进程管理器,每个 worker 内部是 uvicorn 的 ASGI 实例。进程数怎么定?很多人会说 2 倍 CPU 核数加 1,但实际还是要压测。如果服务大量在等数据库和下游,异步框架单 worker 也能扛比较高并发;如果服务是 CPU 密集型,你需要的是更多进程而不是更多协程,因为 Python 的 GIL 在同一个进程里限制并行计算。

容器化部署时,还要考虑 worker 的优雅退出和启动健康检查。别把--workers设得过大,每个进程都要占用内存。尤其在 Kubernetes 环境下,一个 Pod 内跑 8 个 worker 很容易内存爆掉,不如用多个副本更可控。日志也要打到标准输出,方便采集。

4.2 测试、日志与监控:工程化能力对照

Django 自带了一整套测试工具,包括测试客户端、基于数据库事务的隔离、Mock 支持。加上它的 ORM 和模型体系,写集成测试很方便。对大部分业务后台来说,Django 的测试体验是三个里最顺手的,因为很多状态框架都帮你安排好了。

Flask 的测试依赖 pytest 和app.test_client()。需要注意应用上下文和请求上下文,测试里经常要手动with app.app_context():去操作数据库。Flexible 是它的特点,但也就意味着你要自己维护一套测试脚手架。

FastAPI 的测试推荐用TestClient,它基于 httpx,写起来像 requests:

from fastapi.testclient import TestClient from main import app client = TestClient(app) def test_register(): resp = client.post("/register", json={"username": "abc", "email": "a@b.com", "password": "12345678"}) assert resp.status_code == 200

如果要测异步函数逻辑,可以用pytest-asyncio或anyio跑协程测试。FastAPI 还有app.dependency_overrides这个能力,可以把真实依赖替换成测试 Mock,这一点对写复杂业务单测很有帮助。

日志方面,Django 自带 logging 配置,分模块、分 handler 都很成熟。Flask 和 FastAPI 都要自己搭,我的经验是尽早把结构化 JSON 日志接上,不要再用print调试。监控上,几个框架都能接 prometheus_client,FastAPI 写一个中间件就能统计请求耗时和数量。Django 有现成的第三方库集成,Flask 同样有扩展。这部分差距并不致命,但工程化基础越差,项目后期就越痛苦。

4.3 性能优化:先定位瓶颈再动框架

如果你已经部署上线,发现接口慢,别急着怪框架。先看几个最常见的问题:数据库有没有 N+1 查询?序列化字段是不是查了很多不用返回的数据?有没有在请求里同步调用慢接口?缓存有没有用上?这些在任何框架里都是大头。

对 FastAPI 特别要提醒一句:如果你把原本普通def的函数改成async def之后,压测性能反而下降了,大概率是里面用了同步阻塞操作。这会让其他请求全卡在同一个事件循环里。解决办法是:要么保持普通def,要么把阻塞调用换成真正的异步库。举个例子,同步requests.get()换成httpx.AsyncClient.get(),同步数据库驱动换成异步驱动,或者干脆交给 Celery 之类的后台任务去执行,不要在请求周期里等它。

压测工具我常用 locust 或 wrk,先定一个预期并发数,再观察响应时间和错误率。很多时候你以为框架是瓶颈,其实只是某个 Worker 数量不够、连接池满了、数据库慢查询没优化。记住一句话:框架给你的是可能性,性能靠的是整个系统链路。

5. 选型决策清单与踩坑实录

最后这部分是我最想分享的,因为纯理论很容易说,但真正落地的痛点和坑,只有做过项目的人才知道。

5.1 用五个问题快速定位项目需求

如果你看完前面还是拿不定主意,不妨回答下面五个问题,答案基本就出来了。

第一个问题:项目是不是需要一个现成的管理后台?是,优先选 Django。Django Admin 在内部系统里的价值非常高,CRUD、权限、搜索、筛选基本不用自己写,能节省大量开发时间。第二个问题:是否需要高并发、长连接、WebSocket 或 SSE?是,优先考虑 FastAPI。异步 I/O 和 ASGI 协议在这种场景下是天然优势。第三个问题:团队熟悉异步和类型提示吗?不熟,就别强行上 FastAPI,否则会写出一堆把自己都绕晕的协程;不如用 Flask 或 Django 稳扎稳打。第四个问题:项目是一锤子买卖的原型,还是要长期演进的核心系统?原型可以 Flask 一把梭,长期系统我更推荐 Django 或 FastAPI,它们的工程约束更强。第五个问题:你是否非常依赖自动生成的 OpenAPI 文档?是,FastAPI 几乎零成本,其他框架还得单独配工具。

这五个问题交叉下来,大多数项目都能得到一个明确倾向。当然也存在“偏后台但部分对外 API 要高性能”的混合需求,这种情况不用纠结一个框架吃到底,后面我会讲组合方案。

5.2 我实际踩过的坑和对应解法

第一个坑是 Django ORM 的性能坑。我在一个报表类功能里用了大量循环查询,Django ORM 写起来很舒服,但每查一次就多一次数据库往返,结果接口响应时间一直压不下来。后来通过select_related()和prefetch_related()把查询改成 JOIN 和批量查询,才把问题解决。如果你用到 Django,一定要建立这个意识:ORM 便利不等于会帮你优化 SQL,复杂报表该写原生 SQL 就写。

第二个坑是 Flask 的循环导入。早期我用 Flask 时很喜欢在app.py里直接创建 db 对象,然后在蓝图的模块里通过from app import db使用,结果项目一拆模块就出现循环导入。标准解法是搞一个应用工厂(create_app),把 db、migrate、扩展都挂载到 app 上,再通过单独的 extensions 模块初始化,这样蓝图和模型就能安全导入。

第三个坑是 FastAPI 的异步阻塞。我见过同事在async def里写time.sleep(3),本来想模拟延迟,结果整个服务在 3 秒内所有请求都卡住。排查了半天还以为是数据库压力大。后来我给自己定了一条铁律:只要视图函数内部有同步阻塞调用,一律写成普通def;如果是真异步,就确认所有下游调用都走异步客户端。

第四个坑是 Pydantic 升级带来的破坏性变更。早年项目用的 Pydantic v1,后来升级 v2 时,parse_obj变成了model_validate,.dict()变成了.model_dump(),Config类也改成model_config。如果你有旧项目升依赖,不要无脑升级 Pydantic,先看 FastAPI 版本兼容说明。现在新项目直接锁版本,不折腾。

第五个坑是依赖版本不锁。三个框架的周边库更新速度都很快,尤其是 FastAPI 和 Pydantic 这类新项目。我用requirements.txt只写了fastapi>=0.80,结果几个月后部署新环境装了完全不同的新版本,接口行为变了。后来统一改用带哈希锁定的依赖管理方式,才彻底避免部署漂移。这一点看似不起眼,但非常影响线上稳定性。

5.3 最后的选型心法:什么情况别用什么

基于我踩过这些坑,最后给一条比较直白的经验。不要因为 FastAPI 压测数据好看,就把所有服务都重写成异步,尤其是你手头并没有高并发需求,反而会把简单业务写复杂。不要因为 Django 功能全,就在一个团队小工具或者纯读接口服务里硬塞全家桶,Django 项目启动涉及的配置和依赖都会被放大。Flask 适合快速做东西,但如果没有比较好的代码架构习惯,我不建议拿它去做要跑很多年的核心业务系统。

我现在的默认方案是:内部管理后台、运营后台、CMS 这类项目用 Django,因为它省时间且稳定;对外 API、高并发入口、需要异步或者事件流的服务用 FastAPI;Flask 留给快速原型、脚本式接口、内部小工具。不同模块之间不是说只能选一个,完全可以在一个系统里拆开用——比如 Django 负责后台管理,FastAPI 负责对外 API,两个服务通过 HTTP 或消息队列通信。组合使用的架构维护成本肯定比单一框架高,但能换来每个模块都在适合它的位置。选框架不是追时髦,而是选一种和团队、业务匹配的协作方式。希望这篇对比能让你下次面对选型时,不再只凭感觉。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进