首页 > 解决方案 > 上传多个文件并显示进度条

问题描述

我正在开发一个项目(在 Django 中),我在其中创建了一个页面来添加有关文件的数据信息,然后添加文件本身。

在此处输入图像描述


单击“更多数据集”按钮时,它会添加另一个字段以上传另一个文件。

在此处输入图像描述

这样做可以一次性附加最终用户想要的尽可能多的文件。
我需要的是在单击“上传数据集”后上传所有附件,并应显示单个进度条。

到目前为止,我已经浏览了多个教程,但使用Vitor Freitas 的教程已经接近了。
JS代码:

$(function(){
/*$("#add_new_dataset").click(function(){
    $(".file").click();
});*/

$(".file").fileupload({
    dataType: 'json',
    sequentialUploads: true, /* Send the files one by one */
    start: function(e){ /* When the upload process starts, show the modal */
        $("#modal-progress").modal("show");
    },
    stop: function(e){  /* When the upload progress finalizes, hide the modal */
        $("#modal-progress").modal("hide");
    },
    progressall: function(e, data){ /* Update the progress bar */
        var progress = parseInt(data.loaded / data.total * 100, 10),
            strProgress = progress + "%";
            $(".progress-bar").css({"width": strProgress});
            $(".progress-bar").text(strProgress);
    },
    done: function(e, data){
        if(data.result.is_valid){
            $("#gallery tbody").prepend(
                "<tr><td><a href='" + data.result.url + "'>" + data.result.name + "</a></td></tr>"
            );
        }
    }
})
});

模板代码:

<form id="form" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="container-fluid" id="datasets" style="margin: 0px; padding: 0px;">
    <div class="row" onfocusin="populateFilename(this);">
        <label class="col-md-2">User Name :</label>
        <input class="col-md-2" type="text" id="username" name="user_name" value="{{ user.username }}" readonly />
        <label class="col-md-2">Data-set :</label>
        <input class="col-md-2" type="text" placeholder="Enter dataset" name="dataset" required />
        <label class="col-md-2">Creation Date :</label>
        <input class="col-md-2" type="date" placeholder="YYYY-MM-DD" name="creation_date" required />
        <label class="col-md-2">Beam Line:</label>
        <input class="col-md-2" type="text" placeholder="Enter beam line" name="beamline" required />
        <label class="col-md-2">Data-set file:</label>
        <input class="col-md-2 file" type="file" name="file" data-url="{% url 'add_data_sets' %}" data-form-data='{"csrfmiddlewaretoken": "{{ csrf_token }}"}' required />
        <label class="filename"></label>

        <div class="modal fade" id="modal-progress" data-backdrop="static" data-keyboard="false">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h4 class="modal-title">Uploading...</h4>
                    </div>
                    <div class="modal-body">
                        <div class="progress">
                            <div class="progress-bar" role="progressbar" style="width: 0%;">0%</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<div style="align: center; margin-top: 5px;">
    <div class="container btn-group btn-group-justified btn-group-lg">
        <a onmouseup="addRow();" class="btn btn-outline-secondary" style="width: 50%;">More Datasets</a>
        <button type="submit" class="btn btn-outline-primary" name="add_new_dataset" id="add_new_dataset">Submit Data-set</button>
    </div>
</div>


我应该怎么办?我不太擅长 AJAX,但我看不到任何可以将数据发送到服务器端的代码。是这样还是我错过了什么?请忽略我对这个话题的无知,并提前感谢所有人。

编辑:
已根据一些答案重写了 JS 代码。

document.getElementById('add_new_dataset').onclick = function() {
    $(this).preventDefault();

    console.log('Files uploading begin');
    form_data = new FormData();
    const files = document.getElementsByName('file');
    let count = 0;
    for(let i = 0; i < files.length; i++){
        count++;
        form_data.append("file", files[i]);
    }

    $.ajax({
        url: "/add_data_sets",
        dataType: 'json',
        contentType: false,
        processData: false,
        data: form_data,
        type: 'POST',
        success: function(files, response, xhr, pd){
            $('.file').show();
            if(files.status != false){
                $('.progress-bar').val('/location/' + files.filename);

                var fileData = files.filename;
                console.log('Files uploading...');
            }
            else{
                alert(files.filename);
            }
        },
        /*xhrFields: {
            onprogress: function(e) {
                if(e.lengthComputable) {
                    let percentCompleted = e.loaded / evt.total;
                    pBar.style.width = percentComplete;
                    pBar.innerHTML = percentComplete + "%";
                    console.log('Percent complete : ' + percentComplete);
                }
            }
        }*/
        xhr: function(){
            let xhr = $.ajaxSettings.xhr();
            xhr.upload.onprogress = function(e) {
                let percentCompleted = e.loaded / evt.total * 100;
                pBar.style.width = percentComplete;
                pBar.innerHTML = percentComplete + "%";
                console.log('Percent complete : ' + percentComplete);
            };
            return xhr;
        }

    });
//});
};

这只是上传代码块。从客户端到服务器端的数据发送工作完美,但它令人怀疑,因为当代码运行时没有触发“console.log”调用。是不是数据以某种方式正常提交,而这段代码什么也没做。

EDIT2: 一个新的 JS 函数:

function upload() {
        console.log('Upload function begins');
        let pBar = document.getElementsByClassName('progress-bar')[0],
            progressWindow = document.getElementById('modal-progress'),
            formData = new FormData(document.forms.form),
            xhr = new XMLHttpRequest(),
            percent = 0;

        console.log('Form Data created');
        // Start upload
        xhr.upload.onloadstart = function() {
            //$('#modal-progress').hide().fadeIn();
            //progressWindow
        };

        // Track upload progress
        xhr.upload.onprogress = function(event) {
            percent = parseInt(event.loaded / event.total * 100);
            pBar.innerHTML = percent + "%";
            pBar.style.width = percent + "%";
            //console.log(percent + '% completed');
            //console.log('Uploaded event.loaded of event.total');
        };

        // Report if ends with an error
        xhr.upload.onerror = function() {
            console.log('An error has occurred')
        };

        // Track completion: Both successful or not
        xhr.upload.onloadend = function() {
            //$('#modal-progress').fadeOut().hide();
            console.log('Upload complete with or without error ' + xhr.status);
        };

        // Track progress: Triggered on successful completion
        xhr.upload.onload = function() {
            console.log('Uploading complete');
            progressWindow.hidden = True;
        };

        xhr.open("POST", "{% url 'add_data_sets' %}", true);

        // The 'setRequestHeader' function can only be called when xhr is opened.
        //xhr.setRequestHeader('csrfmiddlewaretoken', '{{ csrf_token }}');
        //xhr.setRequestHeader('test-info', 'something');
        xhr.setRequestHeader('Content-Type', 'application/gzip');

        xhr.send(formData);
    }


该功能现在工作正常。它发送数据完全正常,但在开发服务器控制台屏幕上我收到此错误。

Forbidden (CSRF token missing or incorrect.): /accounts/add_data_set/
[22/Feb/2020 15:36:06] "POST /accounts/add_data_set/ HTTP/1.1" 403 2513

我什至检查了记录发送到服务器的 POST 数据,它确实包含 csrf 令牌

<QueryDict: {'csrfmiddlewaretoken': ['WREoIV0aY4B2XyrU7d9Qw8kMwiokXqwWsmbc2QSHX5VQ0EaYjjeuv7PeysMJjecp'], 'user_name': ['rakesh'], 'dataset': ['r'], 'creation_date': ['2020-02-22'], 'beamline': ['r']}>

我有点困惑。这是一个问题吗?

标签: javascriptpythondjangoajax

解决方案


如果您有任何 fileuploader 插件,他们的文档将包含所有内容,或者如果您想要正常的文件上传输入,您可以通过将文件输入绑定到表单数据来发布它们,然后发布操作表单数据和保存图像的操作,然后您可以返回 save图片和显示,这样就可以实现简单的ajax上传。

var form_data = new FormData();                  
        var totalFiles = document.getElementById('file').files.length;
        var count = 0;
        for (var i = 0; i < totalFiles; i++) {
            var file = document.getElementById('file').files[i];
            count++;
            form_data.append("file", file);
        }


$.ajax({
            url: "/uploadingaction",
            dataType: 'json',           
            contentType: false,
            processData: false,
            data: form_data,                             
            type: 'POST',
            success: function (files, response, xhr, pd) {
                $('yourloaderid').hide();                
                if (files.status != false) {                   
                    $('#displayid').val('/location/' + files.filename);

                    var filedata = files.filename;                                        

                } else {
                    alert(files.filename);
                }

            }
        })

推荐阅读