【问题标题】:Asynchronous HTTP call inside HTTP cycle of Django Rest FrameworkDjango Rest Framework的HTTP循环内的异步HTTP调用
【发布时间】:2018-09-13 06:53:47
【问题描述】:

我需要在views.py上我的一个视图集的get_queryset函数上调用外部服务,但我不需要等待外部函数的响应。

如何使以下 requests.post 行刚刚触发并传递到下一行而不等待结果?

class SomeViewSet(viewsets.ModelViewSet):
    def get_queryset(self):
        ....
        requests.post(urlOfApi+token)
        .....
        return Some.objects.all()

【问题讨论】:

  • 尝试写celery task,通过celery进行外部API请求
  • 是最简单的方法吗?
  • 或者你可以使用threading

标签: python django asynchronous django-rest-framework python-asyncio


【解决方案1】:

我实现了一个端点来运行后台任务。当您点击post 时,端点会返回作业的 ID。然后,您可以使用作业任务 ID 访问 get 端点并返回结果,如果作业仍在运行,则返回 in progress

我没有使用celery 来完成这项任务,但我发现django-q 比芹菜更容易,而且django-q 使用了django 已经使用的所有电池。这是我用 django-q 实现的 API View 示例。

from django.urls import reverse
from django_q.models import Task, OrmQ
from django_q.tasks import async, result
from rest_framework.exceptions import NotFound
from rest_framework.response import Response
from rest_framework.views import APIView


def the_function_to_run():
    # do something here
    pass


class YourTaskApiView(APIView):

    def get(self):

        # you mustr construct the get url to take the id
        task_id = self.kwargs.get('task_id')

        try:
            task = Task.objects.get(id=task_id)
        except Task.DoesNotExist:
            task = None

        # here the task is on processing
        if task:
            return Response({
                'id': task_id,
                'result': result(task_id),
                'started': task.started,
                'stopped': task.stopped,
                'status': 'DONE' if task.stopped else 'RUNNING',
                'success': task.success,
            })
        else:
            # here you find the task in the query (not even processed, but waiting for the cluster to process it)
            for q in OrmQ.objects.all():
                if q.task_id() == task_id:
                    task = q.task()
                    return Response({
                        'id': task['id'],
                        'started': task['started'],
                        'status': 'WAITING', # or ON QUEUE
                        'stopped': None,
                        'success': None,
                    })

        return NotFound()


    def post(self, request):

        # run the task as async
        task_id = async(the_function_to_run)

        # create the reverse for the get so the client already has the link to query for
        # the task status
        link = reverse('yourapp:yournamespace:yourview', kwargs={'task_id': task_id}, request=request)
        return Response(data={'task_id': task_id, 'link': link})

【讨论】:

    【解决方案2】:

    您需要为此类工作实现某种后台作业。

    正如评论中提到的 - 一种方法是使用芹菜。

    如果你不想走那条路。您可以尝试以下方法:

    https://django-background-tasks.readthedocs.io/en/latest/

    也许,不如 celery 方式强大,但更易于设置和运行。

    您只需实现一个功能来执行工作(在您的情况下,向另一个服务发出 http 请求),用背景装饰器装饰它。 然后,在您的视图集中,您只需调用该函数,它就会被安排。您甚至可以选择时间。

    【讨论】:

      猜你喜欢
      • 2019-07-31
      • 1970-01-01
      • 2018-07-26
      • 2016-01-09
      • 2019-01-29
      • 2018-10-17
      • 2021-11-07
      • 1970-01-01
      • 2012-09-10
      相关资源
      最近更新 更多