【001】基于Ajax上传文件
原则:如果我们使用Ajax操作在涉及到文件上传时,那就要使用FormData
1.首先要明白:上传文件使用input输入框的类型是file:
2.后台我需要拿到前端传递过来的文件对象,注意文件对象并不在request.post里面,而是在request.files里面:
# 获取文件对象file_obj,如果想获取文件的名字,使用file_obj.name即可 file_obj = request.FILES.get("cFile")
3.contentType:笔者在上一节中说过即客户端告诉服务端决定以什么样的数据编码格式发送给服务端,在请求头中,如果没有特意指定该参数,那么默认就是以urlencoded的形式为我们组装数据。
注意contentType是前端页面在请求向服务端发送数据,具体以什么格式组装数据然后发送过去,就取决于contentType的类型,默认是如下的类型,就是以键值对键值对的形式组装发送过去:
4.根据上面所说,现在我要传输一个文件过去,因为键值对中涉及到一个文件,如果还是按照默认的编码方式发送过去,我们在服务端打印request.body,拿到的只能是一个文件名:
这显然不满足我们的要求,因为我们是需要文件对象的。所以不能采用默认的形式发送数据,因为涉及到二进制数据,怎么设置?昨天使用Ajax直接指定参数即可,现在我使用Form表单来传递包括二进制文件在内的数据,所以需要添加一个参数:enctype,这里我们选中multipart/form-data,如下:
我以后上传图片,音乐等二进制文件时,都可以结合form-data进行使用,当我们修改格式后,就可以看看请求头中的Content-Type:
然后再来看看服务端的打印结果:
request.FILES接收的是文件对象,InMemoryUploadFile是我们拿到的文件句柄,这样就上传头像了!
通过上面的例子可知,form-data既可以支持表单数据,例如我们打印request.POST打印出表单数据,又支持二进制数据,例如图片,音频等文件。但是urlencoded只支持表单数据。这是两者的根本区别,一定要区分开。
request.FILES是一个字典,现在我们得到一个文件对象:
通过文件句柄的name属性打印出图片的名字:
记住使用Ajax上传文件时候,input输入框的类型要修改为button,不要使用submit.
$(""button")表示选择 type="button" 的 <button> 元素和 <input> 元素。
通过Jquery获取二进制文件对象:
使用Ajax上传一个二进制文件时候,如何组装键值对的时候注意取出值:
1.首先通过Jquery拿到文件所属的input标签:
$("#cFile")
2.将Jquery对象转换为Dom对象:
$("#cFile")[0] 此时我们就拿到了dom对象
3.调用dom对象的files方法,拿到一个文件list:Filelist,接下来只需要获取
该文件列表的第一个元素即可:$("#cFile")[0].files[0]即可获取到文件对象
4.那我们能不能按照如下的方式写呢?
按照上述的方式这样写直接报错:
那是因为你传二进制数据,按照表单数据发送肯定是不行的;所以肯定不能按照上面的方式,那么Ajax利用的也是FormData,要想使用Ajax上传二进制文件就需要使用到FormData,我们也不需要什么form表单了,变为如下:
使用如下的形式发送数据:
直接将formData传递过去即可。点击发送依然有问题,那是因为Content-Type默认是urlencoded,现在我使用Ajax发送,那就要修改两个参数,都设置为False
前面我们说过,无论你的Data里面写什么数据,ajax发送的时候都会以contentType规定的格式对你的数据进行编码传送;你默认是urlencoded,那我就以 urlencoded的格式发送过去;如果你修改为Json,那我就以json的格式发送。 但是不是所有的情况都需要进行编码传送,例如我传递一个二进制文件,二进制没有必要进行编码,按照原来的文件格式发送即可。 Ajax发送数据的时候,首先会查看processData的值,如果为True,表明我需要对该数据进行处理后发送,至于做什么样的处理,就得问contentType了,contentType会告诉Ajax是把数据处理成urlencoded的形式,还是json字符串 也就是说两者配合工作,如果设置processData为False,表示我的数据是什么样子,你就将数据发送到服务器,让服务器自己接受。因此processData的值就只有两个,True:表示我对数据进行预处理,至于怎么处理,就是contentType要干的事,为False,那就告诉ajax不做处理,直接发送二进制数据即可。 因此processData设置为False,那么contentType也没用了,直接设置为False,将默认的urlencoded清空掉,如果你不设置,那么它默认又以urlencoded进行发送。
现在你不使用表单形式(urlencoded)的形式进行发送了,那么我传送csrf_token的时候也是二进制,那肯定也过不了,所以我们得在请求头重添加一个X-CSRFToken:
这里是在网页中的input输入框中取值,所以使用csrfmiddlewaretoken,如果从cookie中取值,那就得使用csrftoken,这里要注意区分。
综上所述,上传文件有两种形式:
总结:上传文件有两种方式:
【01】.form表单数据进行提交:
两处修改:1.在form标签后面增加一个属性enctype="multipart/form-data"
2.由于上传的文件是二进制数据,所以还需要修改contentType,让它变为formdata:
【02】使用Ajax提交:
1.实例化表单数据对象:
这里面的数据是表单数据还是非表单数据都可以
2.然后按照FormData实例化的结果发送过去即可:
最后分享一个实际的例子供各位参考:
$(document).ready(function () { // 为每个input输入框绑定的blur事件,并将值通过Ajax发送给后台进行校验 $("#id_username").blur(function () { $.ajax({ url:"/validate_username/", type:"get", data:{"username": $("#id_username").val()}, success:function (data) { if(data.flag){ alert("This username has benn registered"); // $("#error").html("用户名已被注册"); }else{ console.log(data.flag); } } }); $("#register_btn").submit(); }); var handlerPopup = function (captchaObj) { // 成功的回调 captchaObj.onSuccess(function () { function foo() { $(".error").html(""); } var validate = captchaObj.getValidate(); var $formData = new FormData(); $formData.append("username",$(‘#id_username‘).val()); $formData.append("password", $("#id_password").val()); $formData.append("password_again", $("#id_password_again").val()); $formData.append("email", $("#id_email").val()); $formData.append("mobile", $("#id_mobile").val()); $formData.append("avatar_image", $("#avatar_file")[0].files[0]); $formData.append("csrfmiddlewaretoken", $("input[name=‘csrfmiddlewaretoken‘]").val()); $formData.append("geetest_challenge", validate.geetest_challenge); $formData.append("geetest_validate", validate.geetest_validate); $formData.append("geetest_seccode", validate.geetest_seccode); $.ajax({ url: "/pc-geetest/ajax_register_validate", // 进行二次验证 type: "post", dataType: "json", data: $formData, processData: false, contentType:false, success: function (data) { if (data && (data.status === "success")) { // 注册数据满足规则,提示注册成功的信息,3秒后跳转到登入界面 $("#register_success").html("Congratulations For Register"); setTimeout(foo, 3000); } else { //注册数据不满足规则,那就提示错误信息, error_msg是一个字典 // 当第一次提示有3个字段错误的时候,我修改一个错误后,那么还剩下2个,刚才剩下的那个 //错误应该消失,因为这又是一个ajax请求。 $("span").html(""); $(".form-group div").each(function () { //其次应该将input输入框的错误红色提示消掉,根据后面的可知,我们应该将input输入框的父级标签div $(this).removeClass("has-error"); }); $.each(data.error_msg, function (key, value) { console.log(data.error_msg); //1.新建span标签,并增加相应的样式 $span = $("<span>"); $span.addClass("pull-right").css("color", "red").html(value[0]); //2.将span标签放在对应input输入框下面,通过$("#id_"+key)实现 // .parent()是获取input标签的父级标签,要想让整个input输入框变红,必须为div $("#id_"+key).after($span).parent().addClass("has-error"); // 3.判断全局钩子函数中定义的密码是否错误 if(key === "__all__"){ $("#id_password_again").after($span).parent().addClass("has-error"); } }) } } }); }); $("#popup-submit").click(function () { captchaObj.show(); }); // 将验证码加到id为captcha的元素里 captchaObj.appendTo("#popup-captcha"); }; // 验证开始需要向网站主后台获取id,challenge,success(是否启用failback) $.ajax({ url: "/pc-geetest/register?t=" + (new Date()).getTime(), // 加随机数防止缓存 type: "get", dataType: "json", success: function (data) { initGeetest({ gt: data.gt, challenge: data.challenge, product: "popup", offline: !data.success }, handlerPopup); } }); });
Django文件上传:https://www.cnblogs.com/linjiqin/p/3731751.html
https://www.cnblogs.com/zhaopengcheng/p/5633154.html
http://blog.csdn.net/a18852867035/article/details/66976028
https://www.cnblogs.com/nulige/p/6582355.html
原文地址:https://www.cnblogs.com/pyspark/p/8167851.html