簡體   English   中英

我正在嘗試將 celery 應用於 django 中基於 Class 的視圖(apis)。 我怎樣才能做到這一點?

[英]I'm trying to apply celery to Class based view(apis) in django. How can I do this?

將 celery 應用於基於 class 的視圖是否正確? 而且,如果是,我如何將 celery 應用於基於 class 的視圖? 我不能只在 class 中的函數上方應用標記 @app.task。

class ScheduleByFranchiseIdView(generics.RetrieveAPIView):
permission_classes = (IsAdmin,)
serializer_class = ScheduleSerializer
@app2.task
def get(self, request, franchise_id, start = None, end = None):
    if start != None and end != None:
        query1 = Q(student__profile__franchise__exact=franchise_id)
        query2 = Q(start_time__gte=start)
        query3 = Q(end_time__lt=end)
        queryset = Schedule.objects.filter(query1 & query2 & query3).exclude(status=ScheduleStatus.DELETED).order_by('-id')
        serializer = ScheduleSerializer(queryset, many=True)
    else:
        query1 = Q(student__profile__franchise__exact=franchise_id)
        queryset = Schedule.objects.filter(query1).exclude(status=ScheduleStatus.DELETED).order_by('-id')
        serializer = ScheduleSerializer(queryset, many=True)

    return Response(serializer.data)

我正在嘗試測試這個 api,當我調用 HTTP GET 方法來調用這個 api 時,我得到以下錯誤:

Traceback (most recent call last):
  File "C:\Users\Tonyscoding\Desktop\TOCOL\TOCOL_backend\api\testing\test_pagination.py", line 154, in test_admin_schedule_pagination
    response = self.client.get('/api/schedule/by/franchise/simple/1/')
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\rest_framework\test.py", line 286, in get
    response = super().get(path, data=data, **extra)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\rest_framework\test.py", line 203, in get
    return self.generic('GET', path, **r)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\rest_framework\test.py", line 232, in generic
    method, path, data, content_type, secure, **extra)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\django\test\client.py", line 422, in generic
    return self.request(**r)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\rest_framework\test.py", line 283, in request
    return super().request(**kwargs)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\rest_framework\test.py", line 235, in request
    request = super().request(**kwargs)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\django\test\client.py", line 503, in request
    raise exc_value
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\django\views\generic\base.py", line 71, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\rest_framework\views.py", line 505, in dispatch
    response = self.handle_exception(exc)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\rest_framework\views.py", line 465, in handle_exception
    self.raise_uncaught_exception(exc)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\rest_framework\views.py", line 476, in raise_uncaught_exception
    raise exc
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\rest_framework\views.py", line 502, in dispatch
    response = handler(request, *args, **kwargs)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\celery\local.py", line 191, in __call__
    return self._get_current_object()(*a, **kw)
  File "C:\Users\Tonyscoding\Desktop\TOCOL\venv\lib\site-packages\celery\app\task.py", line 392, in __call__
    return self.run(*args, **kwargs)
TypeError: get() missing 1 required positional argument: 'request'

我的 celery 工人得到了任務。 我認為這不是工人的問題..

在您的情況下,下一個場景可能會起作用。 為繁重的工作量創建一個任務:

@app.task
def schedule_by_franchise(franchise_id, start=None, end=None):
    # Do some slow workload, filtering by non-indexed fields or something.
    if start is not None and end is not None:  # is not None ~20% faster than != None
        query1 = Q(student__profile__franchise__exact=franchise_id)
        query2 = Q(start_time__gte=start)
        query3 = Q(end_time__lt=end)
        queryset = Schedule.objects.filter(query1 & query2 & query3).exclude(status=ScheduleStatus.DELETED).order_by('-id')
    else:
        query1 = Q(student__profile__franchise__exact=franchise_id)
        queryset = Schedule.objects.filter(query1).exclude(status=ScheduleStatus.DELETED).order_by('-id')

    # Returns something serializable and what could be used for more faster DB search (founded object primary keys might fits)
    return tuple(queryset.values_list('id', flat=True))

第一次執行 GET 時,您應該創建 Celery 任務,然后將其 TASK_ID 保存在某處以便稍后獲得結果:

from celery.result import AsyncResult


class ScheduleByFranchiseIdView(generics.RetrieveAPIView):
    permission_classes = (IsAdmin,)
    serializer_class = ScheduleSerializer

    def get(self, request, franchise_id, start=None, end=None, task_id=None):
        if not task_id:
            task = schedule_by_franchise.delay(franchise_id, start, end)
            return Response({
                'task': task.task_id,
                'status': 'processing',
                'message': f'Please, try again in 10 seconds with following task_id={task.task_id}',
            })
        else:
            result = AsyncResult(task_id)
            if result.ready():
                ids = result.result
                queryset = Schedule.objects.filter(id__in=ids)
                serializer = ScheduleSerializer(queryset, many=True)
                return Response(serializer.data)
            else:
                return Response({
                    'status': 'not_ready_yet',
                    'message': 'Please, try again in 5 seconds',
                })

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM