如何将Celery返回的数据序列化到Django REST Framework响应中
问题根因分析
你遇到的空响应问题核心是两个错误叠加导致的:
- 你用
filter()查询单个主键对应的对象,返回的是QuerySet查询集合,而非单个模型实例,序列化单个实例时传入集合会直接返回空结果 - 直接在DRF接口中调用
result.get()是同步阻塞逻辑,会完全丧失Celery异步任务的优势,如果任务处理图片耗时较长还会直接触发接口超时
快速修复方案
修改你视图中查询实例和序列化的代码即可解决空响应问题:
class TestSet(viewsets.ModelViewSet): queryset = Test.objects.all() serializer_class = WebsiteURLSerializer def create(self, request, *args, **kwargs): serializer = WebsiteURLSerializer(data=request.data) if serializer.is_valid(): url_site= serializer.validated_data['url'] result = test_call.delay(url_site) # 原错误:filter返回QuerySet,改用get取单个实例,同时注意任务执行超时问题 obj = ModelName.objects.get(pk=result.get()) # 确认WebsiteURLSerializer是适配ModelName的序列化器,否则也会返回空 result_unpacked = WebsiteURLSerializer(obj) return Response(result_unpacked.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @shared_task(name="values") def test_call(url_image): model_instance = ModelName.objects.create() # 你的业务逻辑 model_instance.save() return model_instance.id
更合理的异步实现方案
如果你的图片拉取和处理逻辑耗时超过2秒,完全不建议在接口中阻塞等待Celery任务执行完成,推荐改成异步交互逻辑:
- 接口提交Celery任务后直接返回任务ID给前端,HTTP状态码用202(已接受)
- 前端通过返回的任务ID轮询任务状态,或者接入WebSocket等待任务完成通知
- 任务执行完成后前端再调用查询接口拉取生成的实例数据
示例优化代码:
def create(self, request, *args, **kwargs): serializer = WebsiteURLSerializer(data=request.data) if serializer.is_valid(): url_site= serializer.validated_data['url'] result = test_call.delay(url_site) # 直接返回任务ID,不阻塞等待 return Response({"task_id": result.id}, status=status.HTTP_202_ACCEPTED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # 新增任务状态查询接口 def get_task_status(request, task_id): task = AsyncResult(task_id) if task.ready(): obj = ModelName.objects.get(pk=task.result) return Response(WebsiteURLSerializer(obj).data) return Response({"status": "processing"}, status=status.HTTP_200_OK)
内容的提问来源于stack exchange,提问作者Joseph Adam
相关产品推荐
相关产品推荐

