5.0 KiB
5.0 KiB
ADRF 异步化转换规范(chunyu_project 视图层)
目标
将 DRF 同步视图迁移到 ADRF(Asynchronous Django REST Framework)+ Django 5.x 异步 ORM,实现从视图到数据库的全链路非阻塞。
核心规则
1. 导入替换
from rest_framework.views import APIView→from adrf.views import APIViewfrom rest_framework import generics/rest_framework.generics.XXX→from adrf import generics(或from adrf.generics import ListCreateAPIView等)from rest_framework.viewsets import ModelViewSet/ReadOnlyModelViewSet→from adrf.viewsets import ModelViewSet, ReadOnlyModelViewSetfrom rest_framework.mixins import ...→from adrf import mixins- 保留:
Response,status,permissions,filters,pagination,serializers,django_filters,drf_yasg的导入不变。 get_object_or_404→from adrf.generics import aget_object_or_404(在 async 上下文中使用)
2. 处理器异步化
- 视图类中的 HTTP 方法处理器改为
async def(get/post/put/patch/delete/list/retrieve/create/update/destroy 及自定义 action)。 - ADRF 特性:类内任意一个处理器是 async,dispatch 即走事件循环;残留的同步处理器会被自动
sync_to_async兜底(不会崩,但会占线程池——尽量全部转完)。
3. 同步 ORM → 异步 ORM(Django 5.x,逐个替换,不可遗漏)
| 同步 | 异步 |
|---|---|
Model.objects.get(...) |
await Model.objects.aget(...) |
filter(...).first() |
await Model.objects.filter(...).afirst() |
filter(...).exists() |
await Model.objects.filter(...).aexists() |
filter(...).count() |
await Model.objects.filter(...).acount() |
Model.objects.create(...) |
await Model.objects.acreate(...) |
obj.save() |
await obj.asave() |
obj.delete() |
await obj.adelete() |
queryset.update(...) |
await queryset.aupdate(...) |
for x in queryset: |
async for x in queryset: |
list(queryset) / 切片后遍历 |
results = [x async for x in queryset[start:end]] |
get_object_or_404(...) |
await aget_object_or_404(...) |
len(queryset)(避免) |
acount() |
注意:
- 切片:
queryset[0:10]本身是惰性的,切片可以保留;但取值/遍历必须 async。 - values()/values_list():
[x async for x in Model.objects.filter(...).values(...)]合法。 - select_related/prefetch_related 链:保留,遍历时 async。
- 聚合:
await Model.objects.aggregate(...)(Django 5.x 支持 aggregate 的异步版本是Model.objects.acount等;aggregate()无原生异步 —— 用await sync_to_async(Model.objects.aggregate)(...))。 - 事务
transaction.atomic():在 async 上下文中改为await sync_to_async(fn)()整体包裹,或使用transaction.atomic的异步支持async with transaction.acreate_agent——最稳妥是await sync_to_async(sync_business_fn)()。 - Q 对象/复杂查询:构造部分是同步的,保留。
4. 外部 HTTP 调用
import requests+requests.get/post(...)→ 改用aiohttp(已安装):
import aiohttp
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
async with session.get(url, params=..., headers=...) as resp:
data = await resp.json()
- 文件上传(如百度语音/图片识别)用
aiohttp.FormData()。 - 若改写风险过大(复杂 multipart),可用
await sync_to_async(requests.post)(...)兜底,但要加注释# TODO: aiohttp 化。
5. 必须保持不变
- 所有
@swagger_auto_schema装饰器原样保留(drf-yasg 只附加元数据,与 async 兼容)。 - 所有 permission_classes、authentication_classes、pagination/filter 配置不变。
- URL 路由文件(urls.py)不改 —— as_view() 不变。
- 返回的 JSON 结构、状态码、错误信息完全不变(前端依赖这些契约)。
- Celery
.delay()调用保留(可在 async 中直接调用;如需保险用await sync_to_async(task.delay)(...))。 request.data/request.query_params/request.user用法不变(ADRF 的 AsyncRequest 兼容)。
6. 缓存操作
cache.get/set是同步网络 I/O →await sync_to_async(cache.get)(key)或保持 django-redis 同步调用并用 sync_to_async 包裹。- 简单做法:
from asgiref.sync import sync_to_async,然后await sync_to_async(cache.set)(key, val, ttl)。
7. 文件/验证
- 每改完一个文件执行:
python -m py_compile <file>确保语法正确。 - 不要运行服务器/测试(由主会话统一验证)。
- 不确定某个 ORM 调用是否有异步版本时,用
sync_to_async包裹并加# TODO: async ORM注释 —— 宁可兜底也不要留下裸同步 ORM 调用(会抛 SynchronousOnlyOperation)。
8. 输出要求
- 逐文件报告:改了哪些处理器、哪些 ORM 调用、哪些外部 HTTP、是否有 sync_to_async 兜底点。
- 列出任何你不敢改的复杂点(如嵌套事务、信号)。