React의 셀러리 진행률 표시줄

1. Overview
2. Backend setup
3. Frontend setup

1. 개요

The progress bar is one of the most useful UI components for tracking the actual progress of the task. But It is still a complex task to track the exact progress. In this tutorial, I will guide you to make the progress bar using celery-progress 반응이 있는 라이브러리.

Please check Celery Progress Bars for Django before starting this tutorial.



이 튜토리얼에서는 DRF(Django Rest Framework)를 사용하여 데이터를 서버에 업로드하고 서버에서 데이터를 사전 처리한 다음 응답을 다시 보낼 것입니다. 필자의 경우 데이터 전처리에 2-3분이 소요되므로 react를 사용하여 프론트엔드에서 처리 진행률 표시줄을 시각화하겠습니다.

2. 백엔드 설정

I consider you already set up your Django with celery . 이제 pip를 사용하여 celery-progress 라이브러리를 설치해야 합니다.

pip install celery-progress


celery-progress in urls.py 파일에 끝점 URL을 추가합니다.

from django.urls import re_path, include
re_path(r'^celery-progress/', include('celery_progress.urls')),


예제 함수를 celery_function 로 작성하고 있습니다. 실제 진행률 추적기 기능을 교체해야 합니다.

from celery import shared_task
from celery_progress.backend import ProgressRecorder
import time

@shared_task(bind=True)
def celery_function(self, seconds):
    progress_recorder = ProgressRecorder(self)
    result = 0
    for i in range(seconds):
        time.sleep(1)
        result += i
        progress_recorder.set_progress(i + 1, seconds)
    return result


다음과 같은 Data 모델이 있습니다.

class Data(models.Model):
    name = models.CharField(max_length=100)
    taskId = models.CharField(max_length=200, blank=True)
    ...
    ...
    ...


이제 DRF의 create 클래스에서 ViewSet 메서드를 덮어쓰고 celery_function.delay(time) 함수를 호출합니다.

In my code, my model name is Data, the serializer class is DataSerializer. I used the patch method to append the task_id to the Data model.



class DataViewSet(viewsets.ModelViewSet):
    queryset = Data.objects.all()
    serializer_class = DataSerializer
    permission_classes = [permissions.IsAuthenticated]

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)

        if serializer.is_valid():
            data = serializer.data
            id = data['id']

            task = celery_function.delay(10)

            self.patch(id, {"taskId": task.id})

        return Response({'task_id': task.id}, status=status.HTTP_201_CREATED)

    def patch(self, pk, taskid):
        instance = self.get_object(pk)
        serializer = DataSerializer(
            instance, data=taskid, partial=True)

        if serializer.is_valid():
            serializer.save()


우리는 백엔드에서 모든 것을 설정했습니다. 작업 진행 상황은 다음 URL에서 확인할 수 있습니다. http://localhost:8000/celery-progress/${task_id} .

3. 프론트엔드 설정

In the frontend, I am going to write the custom progress bar using react-bootstrap . The DRF backend will provide us the task progress in this URL: http://localhost:8000/celery-progress/${task_id} . 이제 작업 상태가 완료로 변경될 때까지 이 URL을 재귀적으로 적중해야 합니다. 이를 위해 axios 을 사용하여 진행 상황을 가져옵니다.

이 튜토리얼에서는 react-redux 을 사용하고 있습니다. reduxactions.js 파일에서 두 개의 함수를 만들었습니다. 하나는 데이터를 추가하는 함수(addData )이고 다른 하나는 작업 진행 상황을 가져오는 함수(getProgress )입니다. addData 함수는 서버에 데이터를 추가할 때만 유용합니다.

export const addData = (data) => (dispatch, getState) => {
  axios
    .post(`http://localhost:8000/api/data/`, data)
    .then((res) => {
      dispatch({
        type: ADD_DATA,
        payload: res.data,
      });

      const task_id = res.data?.task_id;
      dispatch(getProgress(task_id));
    })
    .catch((err) =>
      console.log(err)
    );
};

getProgressJSON 응답으로 작업의 실제 진행 상황을 가져옵니다. json 응답의 예는 아래와 같습니다.

{"complete": true, "success": true, "progress": {"pending": false, "current": 100, "total": 100, "percent": 100}, "result": "Done"}


여기에서 getProgress 함수를 재귀적으로 호출하여 작업이 완료될 때까지 현재 진행 상황을 가져옵니다.

export const getProgress = (taskId) => {
  return (dispatch) => {
    return axios
      .get(`http://localhost:8000/celery-progress/${taskId}`)
      .then((res) => {
        dispatch({
          type: PROGRESS_BAR,
          payload: { taskid: taskId, ...res.data },
        });
        if (!res.data.complete && !res.data?.progess?.pending) {
          return dispatch(getProgress(taskId));
        }
      })
      .catch((err) =>
        console.log(err)
      );
  };
};


또한 reduxreducers.js 파일에 다음과 같이 응답을 추가했습니다.

import { ADD_DATA, PROGRESS_BAR } from "../actions/types";

const initialState = {
  progress: {},
  data: [],
};

export default function (state = initialState, action) {
  switch (action.type) {
    case PROGRESS_BAR:
      return {
        ...state,
        progress: action.payload,
      };

    case ADD_DATA:
      return {
        ...state,
        data: action.payload,
      };
    default:
      return state;
  }
}


이제 아래와 같이 진행률 표시줄을 시각화하는 반응 구성 요소를 작성해 보겠습니다.

import React, { Component } from "react";
import { connect } from "react-redux";
import { ProgressBar } from "react-bootstrap";

class ProgressBarUi extends Component {
  render() {
    const { percent } = this.props;
    return (
      <ProgressBar
        now={percent}
        animated
        variant="success"
        label={`${percent}%`}
      />
    );
  }
}

export default ProgressBarUi;


진행률 표시줄은 진행 상황이 완료되지 않고 보류 중이 아닌 경우에만 시각화해야 합니다.

import React, { Component } from "react";
import { connect } from "react-redux";
import { addData } from "../../../actions";
import ProgressBarUi from "../../common/ProgressBar";

class AddData extends Component {
  onSubmit = (e) => {
    const data = {
      key1: "value1",
      key2: "value2",
    };
    this.props.addExposure(data);
  };

  render() {
    const { progress } = this.props;

    return (
      <div>
        {/* your progress bar goes here  */}
        {progress?.progress && !progress?.complete && (
          <ProgressBarUi percent={progress.progress?.percent} />
        )}

        ...
        ...
        ...
        {/* data submit button */}
        <input type="submit" value="Add data" onSubmit={this.onSubmit} />
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  progress: state.progress,
});

export default connect(mapStateToProps, {
  addData,
})(AddData);


자, 마침내 Django, react, celery를 사용하여 진행률 표시줄을 성공적으로 설정했습니다.

좋은 웹페이지 즐겨찾기