搜索
您的当前位置:首页正文

Django - 如何上传文件?

来源:二三娱乐
目标

在很多Web应用中,都有上传文件的使用场景。本篇文件将讲述如何使用一个Form表单上传文件,该Form表单将包含一个select input和一个file input。

form is not invalid ?

前端HTML5文件的Form描述是

<form>
    <div class="row justify-content-center align-items-center">
        <label class="col-sm-8 col-form-label text-align:center">初次使用请先下载商品模板</label>
        <div class="col-sm-4">
            <button class="btn green" type="button" id="downloadSKUTemplate">下载
                <i class="fa fa-download"></i>
            </button>
        </div>
    </div>

    <div class="justify-content-center align-items-center">
        <label for="storesel" class="col-sm-8 col-form-label">导入门店: </label>
\                       <div class = "col-sm-4">
            <select class="bs-select green form-control pull-right" id="storesel" data-style="btn-info" name="store">
                <option value="NULL" selected="selected">--请选择门店--</option>
                <option value="CO">Colorado</option>
                <option value="ID">Idaho</option>
                <option value="MT">Montana</option>
                <option value="NE">Nebraska</option>
                <option value="NM">New Mexico</option>
                <option value="ND">North Dakota</option>
                <option value="UT">Utah</option>
                <option value="WY">Wyoming</option>
            </select>
        </div>
    </div>

    <div class="form-group">
        <div class="fileinput fileinput-new" data-provides="fileinput">
            <span class="btn btn-default btn-file">
                <span class="fileinput-new">Select file</span>
                <span class="fileinput-exists">Change</span>
                <input id="skuimport" type="file" name="skufile"></span>
            <span class="fileinput-filename"></span>
            <a href="#" class="close fileinput-exists" data-dismiss="fileinput" style="float: none">&times;</a>
        </div>
    </div>                    
</form>

前端JS文件的实现是


            function sendXHRequest(formData, uri) {
                console.info("+++ sendXHRequest +++");
                // Get an XMLHttpRequest instance
                var xhr = new XMLHttpRequest();

                  xhr.upload.addEventListener('loadstart', onloadstartHandler, false);
                  xhr.upload.addEventListener('load', onloadHandler, false);
                  xhr.addEventListener('readystatechange', onreadystatechangeHandler, false);
                // Set up request
                xhr.open('POST', uri, true);

                for(var value of formData.values()){
                    console.log(value);
                }
                xhr.setRequestHeader("X-CSRFToken",csrftoken);
                //xhr.setRequestHeader("Content-Type", "multipart/form-data");

                // xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=AaB03x");
                // Fire!
                xhr.send(formData);
                console.info(" --- sendXHRequest ---");
            }

            function initFullFormAjaxUpload() {
                var form = document.getElementById('testform');

                // FormData receives the whole form
                console.info("+++ initFullFormAjaxUpload +++");
                var formData = new FormData();


                //FormData only has the file
                var fileInput = document.getElementById('skuimport');
                var file = fileInput.files[0];
                formData.append('file', file);
                formData.append('store',$('#import #storesel').val());
                //Code common to both variants
                sendXHRequest(formData, 'skuimport/');
                console.info("--- initFullFormAjaxUpload ---");

            }


            $('#import #btn-confirm').click(function(event)
            {

                event.preventDefault();
                alert("import form button confirm clicked");
                initFullFormAjaxUpload();
                alert("import form button confirm done");

                $('#import').modal('hide');
            });

Django后台view的实现是

class skuimport(generic.View):
    def get(self, request):
        pass
    def post(self,request):
        print "skuimport POST +++"
        if request.method == "POST":
            print "sku skuimport"
            for key in request.POST:
                print key
                value = request.POST.getlist(key)
                print value
        
            form = UploadFileForm(request.POST, request.FILES)

            if form.is_valid():
                print "form is valid"
                handle_uploaded_file(request.FILES['skufile'],"skufile.jpg")
            else:
                print "form is not valid"
            return render(request,'p_test.html',{'form': form} )

Django后台的Form的定义是

class UploadFileForm(forms.Form):
    skufile = forms.FileField()
    store = forms.CharField()

按照我的理解,上述实现基本上是按照官网描述的方法实现的, 但是结果却出人意料。后台的输出如下:

skuimport POST +++
sku skuimport
store
[u'NULL']
form is not valid
怎么调试?
return render(request,'p_test.html',{'form': form} )
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% for field in form %}  
  <div class="fieldWrapper">  
      {{ field.errors }}  
      {{ field.label_tag }} :test: {{ field }}  
  </div>  
{% endfor %}  
</body>
</html>

在js里面定义回调函数

 // Handle the response from the server
            function onreadystatechangeHandler(evt) {
              var status, text, readyState;
              try {
                readyState = evt.target.readyState;
                text = evt.target.responseText;
                status = evt.target.status;
              }
              catch(e) {
                return;
              }
              if (readyState == 4 && status == '200' && evt.target.responseText) {
                alert(evt.target.responseText);
                $('#import').modal('hide');

              }
            }

这样我们在上传文件之后,浏览器会弹出如下图所示信息:


错误信息
解决办法
情况1:

在发送XHRRequest请求的时候, 该函数formData.append('file', file);中的第一个参数‘file’必须和Django后端Form类里面定义的变量名保持一致。 在本例子中即是:

class UploadFileForm(forms.Form):
    skufile = forms.FileField()
    store = forms.CharField()

如果是使用XHRRequest发送FormData,那么在使用append方法的时候, 就必须使用“skufile”和“store”作为第一个参数名:

formData.append('file', file);
formData.append('store',$('#import #storesel').val());
情况2:

如果在Form中使用action/submit直接上传,那么每一个input控件的name必须和Django后台Form类中的参数名保持一致。 这样才能避免因为名字不一样而导致的错误

下期预告

下一篇文章将讲述:如何解决怎么在上传文件的时候前端显示进度

Top