首页 > 解决方案 > 在 Django 中使用 AJAX 获取 celery 进度

问题描述

我是 Web 开发的新手。我想上传一个文件并在 Celery 任务中处理它,并使用 AJAX 显示进度百分比。我使用了一些这样的示例,是我的代码:

视图.py:

def importnewdata(request):

    if request.method == 'POST':
        form = RawFileAddressForm(request.POST, request.FILES)
        if form.is_valid():
            file = request.FILES['file']
            file_name = default_storage.save("sample.txt", file)
            task = process_file.delay(file_name)
            return HttpResponse(json.dumps({'task_id': task.id}), content_type='application/json')
        else:
            return HttpResponse("Error1!")
    else:

        form = RawFileAddressForm()
        return render(request, 'modelmanager/importnewdata.html', {'form': form})



def get_task_info(request):
    task_id = request.GET.get('task_id', None)
    if task_id is not None:
        task = AsyncResult(task_id)
        data = {
            'state': task.state,
            'result': task.result,
        }
        return HttpResponse(json.dumps(data), content_type='application/json')
    else:
        return HttpResponse('No job id given.')

表格.py:

class RawFileAddressForm(forms.Form):
    file = forms.FileField()

导入新数据.html:

<!DOCTYPE html>
<html>
<head>
    <title>import new raw data to db</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

</head>
<body style="text-align: center;">

    <h1>select your file to process it!</h1>
    <progress id="progress-bar" value="0" max="100" style="display:none; margin-bottom: 1em;"></progress>

    <form id="process-raw-data" action="/modelmanager/importnewdata/" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        {{  form  }}
        <input type="submit" value="Submit"/>
    </form>

<script type="text/javascript">
    var frm = $('#process-raw-data');
    var pgrbar = $('#progress-bar');

    frm.submit(function () {
        $.ajax({
            type: frm.attr('method'),
            url: frm.attr('action'),
            data: frm.serialize(),
            success: function (data) {
                if (data.task_id != null) {
                    get_task_info(data.task_id);
                }
            },
            error: function (data) {
                frm.html("error!");
            }
        });
        return false;
    });

    function get_task_info(task_id) {
        $.ajax({
            type: 'get',
            url: '/modelmanager/get-task-info/',
            data: {'task_id': task_id},
            success: function (data) {
                frm.html('');
                if (data.state == 'PENDING') {
                    frm.html('Please wait...');
                }
                else if (data.state == 'PROGRESS') {
                    pgrbar.css('display', 'inline');
                    pgrbar.val(data.result.percent);
                    frm.html('lines processed ' + data.result.current + ' out of ' + data.result.total);
                }
                else if(data.state == 'SUCCESS'){
                    pgrbar.css('display', 'none');
                    frm.html('Successfully Completed!');

                }
                if (data.state != 'SUCCESS') {
                    setTimeout(function () {
                        get_task_info(task_id)
                    }, 500);
                }
            },
            error: function (data) {
                frm.html("error!");
            }
        });
    }
</script>


</body>
</html>

问题是单击提交按钮后没有任何反应。我有:

“POST /modelmanager/importnewdata/HTTP/1.1”200 10

在 Wireshark 我看到

错误1!

作为回应。这意味着表单无效,但是当我从 html 文件中删除 JS 部分时,它会返回一个带有成功创建的 celery 任务 ID 的 json 对象。这意味着表单是有效的。任何帮助。谢谢。

标签: jquerydjangoajaxcelery

解决方案


谢谢大家。你帮了我很多!:)

最后,这是我的解决方案:

视图.py:

def importnewdata(request):

    cntx = {}
    if request.method == 'POST':
        form = RawFileAddressForm(request.POST, request.FILES)
        if form.is_valid():
            file = request.FILES['file']
            file_name = default_storage.save("sample.txt", file)
            task = process_file.delay(file_name)
            cntx['task_id'] = task.id
            return render(request, 'modelmanager/importnewdata.html', cntx)
        else:
            return render(request, 'modelmanager/importnewdata.html', {'form':form})
    else:

            form = RawFileAddressForm()
            return render(request, 'modelmanager/importnewdata.html', {'form': form})

def get_task_info(request):
    task_id = request.GET.get('task_id', None)
    if task_id is not None:
        task = AsyncResult(task_id)
        data = {
            'state': task.state,
            'result': task.result,
        }
        return HttpResponse(json.dumps(data), content_type='application/json')
    else:
        return HttpResponse('No job id given.')

导入新数据.html:

<!DOCTYPE html>
<html>
<head>
    <title>import new raw data to db</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

</head>
<body style="text-align: center;">

    <h1>select your file to process it!</h1>
    <progress id="progress-bar" value="0" max="100" style="display:none; margin-bottom: 1em;"></progress>

    <form id="process-raw-data" action="/modelmanager/importnewdata/" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        {{  form  }}
        <input type="submit" value="Submit" />
    </form>

{% if task_id %}
    <script type="text/javascript">
        var taskid = "{{task_id}}";
        var frm = $('#process-raw-data');
        var pgrbar = $('#progress-bar');

        get_task_info(taskid);

        function get_task_info(tid) {
            $.ajax({
                type: 'get',
                url: '/modelmanager/get-task-info/',
                data: {'task_id': tid},
                success: function (data) {
                    frm.html('');
                    if (data.state == 'PENDING') {
                        frm.html('Please wait...');
                    }
                    else if (data.state == 'PROGRESS') {
                        pgrbar.css('display', 'inline');
                        pgrbar.val(data.result.percent);
                        frm.html('lines processed ' + data.result.current + ' out of ' + data.result.total);
                    }
                    else if(data.state == 'SUCCESS'){
                        pgrbar.css('display', 'none');
                        frm.html('Successfully Completed!');

                    }
                    if (data.state != 'SUCCESS') {
                        setTimeout(function () {
                            get_task_info(tid)
                        }, 500);
                    }
                },
                error: function (data) {
                    frm.html("error!");
                }
            });
        }
    </script>
{% endif %}


</body>
</html>

推荐阅读