75 lines
5.0 KiB
Markdown
75 lines
5.0 KiB
Markdown
# 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 <file>` 确保语法正确。
|
||
- 不要运行服务器/测试(由主会话统一验证)。
|
||
- 不确定某个 ORM 调用是否有异步版本时,用 `sync_to_async` 包裹并加 `# TODO: async ORM` 注释 —— 宁可兜底也不要留下裸同步 ORM 调用(会抛 SynchronousOnlyOperation)。
|
||
|
||
### 8. 输出要求
|
||
- 逐文件报告:改了哪些处理器、哪些 ORM 调用、哪些外部 HTTP、是否有 sync_to_async 兜底点。
|
||
- 列出任何你不敢改的复杂点(如嵌套事务、信号)。
|