Django异步视图必须搭配ASGI服务器(如Uvicorn),WSGI不支持;ORM和requests需用sync_to_async或httpx.AsyncClient包装;中间件、装饰器须适配async,否则全链路降级为同步。

async def 视图函数必须搭配 ASGI 服务器
Django 的异步视图(async def)在 WSGI 下直接报错,不是写法问题,是运行时环境不支持。WSGI 协议本身是同步阻塞的,根本无法挂起协程;只有 ASGI(如 Uvicorn 或 Daphne)能调度 await 表达式。
常见错误现象:RuntimeError: async def view used on a synchronous server
- 开发时用
python manage.py runserver—— 默认还是 WSGI,哪怕视图写了async def也会静默退化成同步执行,甚至不报错但完全没异步效果 - 必须显式换 ASGI 服务:启动命令改成
uvicorn myproject.asgi:application - 确认项目已启用 ASGI:检查是否存在
asgi.py,且内容调用的是get_asgi_application() - Django 3.1+ 才真正支持原生 async 视图,低于此版本即使配了 ASGI 也无效
数据库操作不能直接 await,得用 sync_to_async 包装
Django ORM 默认全是同步阻塞调用,Model.objects.get()、.save() 这些方法内部会直接阻塞事件循环。直接在 async def 视图里调用,会导致整个异步服务卡住——表面跑起来了,实际并发能力归零。
使用场景:需要查库 + 调第三方 API(如 HTTP 请求)的混合 IO 场景,比如「查用户信息 + 调支付网关」
- 别写
await User.objects.get(id=1)—— 语法错误,ORM 方法不返回Awaitable - 正确做法是用
sync_to_async包一层:user = await sync_to_async(User.objects.get)(id=1) - 注意:
sync_to_async本质是把同步调用扔进线程池执行,有上下文切换开销,不适合高频小查询;大批量数据建议先用list()拉到内存再处理 - 模型方法自定义逻辑(如
user.get_profile())同样要包装,不能假设它“自动异步”
HTTPX 替代 requests,否则 await requests.get() 会死锁
requests 是纯同步库,底层用 urllib3 + 阻塞 socket,放进 async def 里 await requests.get(...) 不仅无效,还可能让事件循环饿死。Python 解释器不会报错,但请求永远不返回。
性能影响:同步 HTTP 客户端在异步视图里等于“一个请求占一个线程”,彻底废掉 async 的轻量协程优势
- 必须换异步 HTTP 客户端:推荐
httpx.AsyncClient(API 兼容requests,支持async with) - 示例:
async with httpx.AsyncClient() as client: resp = await client.get("https://api.example.com/data") - 别用
aiohttp除非已有深度集成——httpx对 Django 生态更友好,支持 HTTP/2、mock 更方便 - 第三方 SDK(如 Stripe、SendGrid)若没提供 async 接口,仍需
sync_to_async包装,不能硬 await
中间件和装饰器默认不兼容 async,容易漏掉关键链路
Django 中间件(尤其是认证、CSRF、日志类)多数是同步写的,放在 async 视图前,会强制把整个请求流程降级为同步执行——你写了 async def,但中间件一拦,后面全白搭。
容易踩的坑:本地测试一切正常,上线后压测发现 QPS 上不去,排查半天发现是某个自定义中间件没适配
- Django 自带中间件中,只有明确标为 “ASGI-aware” 的才安全(如
SecurityMiddleware),SessionMiddleware和AuthMiddleware在 4.1+ 才完整支持 async - 自定义中间件必须写成
async def __call__,且内部所有调用(包括get_response)都要 await - @login_required 这类装饰器不支持 async 视图,会报
TypeError: object Response can't be used in 'await' expression;改用AsyncLoginRequired或手动检查request.user.is_authenticated - 日志中间件如果用了
time.time()+ 同步文件写入,也会拖慢整个事件循环,建议改用异步日志库或至少丢进线程池
async 视图不是加个 async 关键字就完事,从服务器、ORM、HTTP 客户端到中间件,每个环节都得对齐异步契约。漏掉任意一环,性能提升就归零,还可能引入隐蔽的竞态或超时问题。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











