Django+Celery任务查询模型返回数据出现AsyncResult无法序列化报错如何解决
错误根因
- 调用
get_all.delay()返回的是AsyncResult类型的异步任务实例,而非任务的实际执行结果,你直接将该实例传入序列化器和Response对象,自然无法完成JSON序列化 - 即便你后续获取到任务返回值,当前任务中直接返回Django ORM查询集对象,Celery默认的JSON序列化器也不支持序列化模型类实例,依然会抛出序列化错误
解决方案
根据你的业务场景选择对应方案即可:
方案1:接口需要同步返回查询结果(适配你当前的需求)
你需要对两个文件的代码做调整:
- 修改
tasks.py,将序列化逻辑移入任务内部,直接返回可JSON序列化的字典列表:
from celery.decorators import task from .models import Dummy from .serializers import DummySerializer @task(name="get_all") def get_all(): dummies = Dummy.objects.all() # 任务内提前完成序列化,返回标准可序列化数据 return DummySerializer(dummies, many=True).data
- 修改
views.py,触发任务后等待执行完成再拿结果返回:
from rest_framework import status from rest_framework.response import Response @api_view(["GET"]) @authentication_classes([]) @permission_classes([]) def dummy_list_all(request): """ list all dummy objects """ if request.method == "GET": # 触发异步任务 task_obj = get_all.delay() # 等待任务执行完成,timeout可根据业务需求调整 result_data = task_obj.get(timeout=10) return Response(result_data, status=status.HTTP_200_OK)
注意:这种同步等待任务执行的模式,性能和直接在视图内执行查询没有差异,如果没有特殊的异步解耦需求,不需要把简单查询逻辑放到Celery中执行,直接在视图内查询返回即可。
方案2:纯异步场景(接口不需要同步返回结果)
如果业务允许前端后续拿结果,可采用任务ID轮询的方案:
- 新增任务结果查询接口:
from celery.result import AsyncResult from rest_framework import status from rest_framework.response import Response @api_view(["GET"]) def query_task_result(request, task_id): task = AsyncResult(task_id) if task.ready(): return Response({"status": "success", "data": task.result}, status=status.HTTP_200_OK) return Response({"status": "pending"}, status=status.HTTP_102_PROCESSING)
- 调整原视图逻辑,触发任务后直接返回任务ID:
@api_view(["GET"]) @authentication_classes([]) @permission_classes([]) def dummy_list_all(request): """ list all dummy objects """ if request.method == "GET": task_obj = get_all.delay() return Response({"task_id": task_obj.id}, status=status.HTTP_202_ACCEPTED)
前端拿到task_id后,轮询调用query_task_result接口获取最终结果即可。
内容的提问来源于stack exchange,提问作者digdigdoot
相关产品推荐
相关产品推荐

