# ADRF 异步化转换规范(chunyu_project 视图层) ## 目标 将 DRF 同步视图迁移到 ADRF(Asynchronous Django REST Framework)+ Django 5.x 异步 ORM,实现从视图到数据库的全链路非阻塞。 ## 核心规则 ### 1. 导入替换 - `from rest_framework.views import APIView` → `from adrf.views import APIView` - `from 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, ReadOnlyModelViewSet` - `from 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`(已安装): ```python 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 ` 确保语法正确。 - 不要运行服务器/测试(由主会话统一验证)。 - 不确定某个 ORM 调用是否有异步版本时,用 `sync_to_async` 包裹并加 `# TODO: async ORM` 注释 —— 宁可兜底也不要留下裸同步 ORM 调用(会抛 SynchronousOnlyOperation)。 ### 8. 输出要求 - 逐文件报告:改了哪些处理器、哪些 ORM 调用、哪些外部 HTTP、是否有 sync_to_async 兜底点。 - 列出任何你不敢改的复杂点(如嵌套事务、信号)。