Files
chunyu_project/docs/ADRF_CONVERSION_GUIDE.md

5.0 KiB
Raw Permalink Blame History

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(已安装):
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 兜底点。
  • 列出任何你不敢改的复杂点(如嵌套事务、信号)。