Django 3.1+已原生支持async def视图,5.0进一步完善;关键在于异步能力分层且有边界,async声明仅使入口协程化,ORM、中间件、模板等默认仍同步,遇同步调用即触发SynchronousOnlyOperation异常而非静默降级。

Django 原生不支持异步视图操作——这个说法本身是错的。Django 3.1+ 就已原生支持 async def 视图,5.0 更完善;真正的问题不是“不支持”,而是**它不自动让所有代码变异步**。
关键点在于:Django 的异步能力是分层的、有边界的。你写 async def 只是声明了入口是协程,但里面调用的 ORM、中间件、模板、缓存等,默认全是同步的。一旦碰到 User.objects.get() 或 request.session.save() 这类同步阻塞调用,整个请求链路就卡住——不是 Django 拒绝异步,而是它主动拦截并抛出 SynchronousOnlyOperation 异常,防止事件循环被拖垮。
所以不是“不支持”,而是“不纵容混用”。
为什么 Django ORM 默认仍是同步的?
Django ORM 底层基于 DB-API 2.0(如 psycopg2、sqlite3),这些驱动全是同步阻塞 I/O。重写整个 ORM 为异步需重构连接池、查询编译、结果映射、事务管理等模块,还要兼容所有后端(PostgreSQL/MySQL/SQLite)。这不是加个 async 关键字就能解决的事。官方选择渐进式路径:aget()、aall() 等方法在 5.0 才稳定,且仅限 PostgreSQL 和 SQLite(MySQL 驱动仍无官方 async 支持)。
为什么中间件默认不异步?
很多中间件依赖线程本地存储(threading.local)维护 request/session/csrf 状态。异步环境下,协程可能跨线程调度,threading.local 失效。Django 提供了 AsyncMiddlewareMixin,但旧版 SessionMiddleware、CsrfViewMiddleware 仍为纯同步实现。只要其中任意一个没升级,整个请求就得退化到线程模型运行——Django 不会偷偷帮你降级,而是明确用日志提示 “Synchronous middleware adapted”。
为什么不能直接 await requests.get()?
requests 底层用的是阻塞 socket,放进事件循环里 await 它,等于让整个协程挂起等待系统调用返回,和同步无异。Python 解释器不会报错,但请求永远不回来。这不是 Django 的限制,是 requests 自身设计决定的。必须换 httpx.AsyncClient 或 aiohttp 这类真正基于 asyncio 的客户端。
真正容易被忽略的点是:**async 视图的性能收益只在 I/O 密集、且整条链路无同步阻塞点时才成立**。写个 async def 然后里面全包 sync_to_async,反而因线程池调度开销更慢。要不要异步,得看你的瓶颈是不是数据库/HTTP/Redis —— 而不是看语法是否用了 async。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











