Django文件上传与获取多个值(三)
一、一个简单的文件上传的方式
官网:https://docs.djangoproject.com/en/2.0/topics/http/file-uploads/
urls.py加一条路由视图:
url(r'upload',views.upload),
主站views.py上加upload函数:
from django.shortcuts import HttpResponse from django.shortcuts import render import datetime from django.shortcuts import redirect from django.core.files.uploadedfile import InMemoryUploadedFile import os def upload(request): if request.method == "GET": return render(request, 'upload.html') else: ff = request.POST.get('fafile') obj = request.FILES.get('fafile') #获取文件 print(ff, obj, type(obj), obj.name) ##ff应该会输出None,obj是文件,看类型就不单单是文件名,obj.name为文件名 file_path = os.path.join('upload', obj.name) ##在指定文件前面加上上传目录位置 f = open(file_path, mode="wb") #f = open(obj.name, mode="wb") #打开一个文件进行文件接收,但是这样不能指定文件位置 for i in obj.chunks(): #chunks是把文件分块,数据本来就是一块块的进行传输的 f.write(i) f.close() return render(request, 'upload.html')
#InMemoryUploadedFile #这个是加载用户上传文件模块
再有一个upload.html:
<body> <form action="/upload" method="post" enctype="multipart/form-data"> <p> <input type="file" name="fafile"> </p> <p><input type="submit" value="提交"></p> </form> </body>
#enctype="multipart/form-data"加上这句话就是文件以文件形式传输到后台,不然只是把文件名称传过去
#然后再创建一个upload目录用于存放upload的内容。
下面是测试内容:
#从上图可以看到 ff = request.POST.get('fafile') #这个只能获取字符串,但是当前端html页面以文件形式传输时这里就获取不到值了。
#上图是django后台抓到的打印信息。
#可以看到已经将上传的内容存放到了指定的目录下面。客户端发来请求发到服务端,有请求头,请求尾,服务端会根据请求头里的信息做提取,django会把表单这些内容提取到POST中,把文件提取到FILE中。
request.FILES中的值均为UploadedFile类文件对象。
UploadedFile是类文件对象,具有以下方法和属性:
UploadedFile.read() #读取整个上传文件的数据,文件较大时慎用,可能会耗尽内存。 UploadedFile.multiple_chunks(chunk_size=None) #如上传文件足够大,要分成多个部分读入时,返回True.默认情况,当上传文件大于2.5M时,返回True。但这一个值可以配置。 UploadedFile.chunks(chunk_size=None) #返回一个上传文件的分块生成器。如multiple_chunks()返回True,必须在循环中使用chrunks()来代替read()。一般情况下直接使用chunks()就行。 UploadedFile.name #上传文件的name。 UploadedFile.size #上传文件的大小(字节)。 UploadedFile.content_type #上传文件时的content_type报头,例如(e.g. text/plain or application/pdf). UpladedFile.charset #编码
二、getlist获取多个值
urls.py加一条路由视图:
url(r'zhuce',views.zhuce),
主站views.py上加zhuce函数:
def zhuce(request): if request.method == "GET": return render(request,'zhuce.html') elif request.method == "POST": v = request.POST.get('gender') f = request.POST.getlist('favor') c = request.POST.get('city') c2 = request.POST.getlist('city2') print(v, f, c, c2) return render(request, 'zhuce.html')
zhuce.html的配置:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <link rel="stylesheet" href="/static/commons.css" /> <body> <form action="/zhuce" method="post"> <p> <input type="text" name="user" placeholder="用户名" /> </p> <p> <input type="password" name="pwd" placeholder="密码" /> </p> <p> 男:<input type="radio" name="gender" value="1" /> 女:<input type="radio" name="gender" value="2"/> 人妖: <input type="radio" name="gender" value="3" /> </p> <p> 篮球:<input type="checkbox" name="favor" value="1"> 足球:<input type="checkbox" name="favor" value="2"> 排球:<input type="checkbox" name="favor" value="3"> </p> <p> <select name="city"> <option value="sh">上海</option> <option value="bj">北京</option> <option value="tj">天津</option> </select> </p> <p> <select name="city2" multiple> <option value="sh">上海</option> <option value="bj">北京</option> <option value="tj">天津</option> </select> </p> <p><input type="submit" value="提交"></p> </form> <script src="/static/jquery.min.js"></script> </body> </html>
#从django后台打印的post信息可以看到多选框里面的内容是列表的形式。
三、Ajax文件上传
3.1 ajax原生实现上传
urls.py:
url(r'^upload/$',views.upload), url(r'^upload_file/$',views.upload_file),
upload.html :
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .upload{ display: inline-block;padding: 10px; background-color: brown; position: absolute; top: 0; bottom: 0; right: 0; left: 0; z-index: 90; } .file{ width: 100px;height: 50px;opacity: 0; position: absolute; top: 0; bottom: 0; right: 0; left: 0; z-index: 100; } </style> </head> <body> <div style="position: relative;width: 100px;height: 50px;"> <input class="file" type="file" id="fafafa" name="afafaf" /> <a class="upload">上传</a> </div> <input type="button" value="提交XHR" onclick="uploadXHR();"> <script> //使用原生ajax实现上传 function uploadXHR(){ //首先获取值 //$("#fafafa")[0]==document.getElementById("fafafa") //files表示你要上传的文件,上传的file可能有多个,但是我们这里只有一个所以是0, var file_obj=document.getElementById("fafafa").files[0]; //拿文件的话要加.files,这就取出了要上传的文件对象 //这里file_obj是对象,send发送的是字符串,所以不能直接发送 var formdata=new FormData();//FormData表示是一个form表单 formdata.append("username","root");//可以加普通的值如key ,value formdata.append("fafafa",file_obj);//可以加对象 //设置原生ajax对象 var xhr= new XMLHttpRequest(); xhr.open("POST","/upload_file/",true); //回调函数,当状态变化时触发 xhr.onreadystatechange=function () { if(xhr.readyState == 4){ //表示接收完毕 console.log(xhr.responseText); var obj = JSON.parse(xhr.responseText); console.log(obj) } }; //上传文件不需要设置请求头 xhr.send(formdata);//发送的数据只能是字符串 } </script> </body> </html>
views.py:
def upload(request): return render(request,'upload.html') def upload_file(request): username=request.POST.get("username") file_obj=request.FILES.get("fafafa") print(username,file_obj) with open(file_obj.name,'wb') as f: for item in file_obj.chunks(): f.write(item) ret={"status":False,"data":request.POST.get("username")} return HttpResponse(json.dumps(ret))
测试一下:
#可以看到文件上传上来了。基于原生的ajax是可以上传文件的,但是要借助于FormData()这个方法。
3.2 ajax jquery实现上传
upload.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .upload{ display: inline-block;padding: 10px; background-color: brown; position: absolute; top: 0; bottom: 0; right: 0; left: 0; z-index: 90; } .file{ width: 100px;height: 50px;opacity: 0; position: absolute; top: 0; bottom: 0; right: 0; left: 0; z-index: 100; } </style> </head> <body> <div style="position: relative;width: 100px;height: 50px;"> <input class="file" type="file" id="fafafa" name="afafaf" /> <a class="upload">上传</a> </div> <input type="button" value="提交jqury" onclick="uploadJquery();"> <script src="/static/jquery-1.12.4.js"></script> <script> //jqury实现上传 function uploadJquery(){ //首先获取值 //$("#fafafa")[0]==document.getElementById("fafafa") //files表示你要上传的文件,上传的file可能有多个,但是我们这里只有一个所以是0, var file_obj=document.getElementById("fafafa").files[0] //这里file_obj是对象,send发送的是字符串,所以不能直接发送 var formdata=new FormData();//FormData表示是一个form表单 formdata.append("username","root");//key ,value formdata.append("fafafa",file_obj);//可以加对象,可以被send发送 $.ajax({ url: '/upload_file/', type: 'POST', data: formdata, processData: false, //tell jQuery not to process the data上传文件要设置,告诉jqury不要做特殊的处理 contentType: false, //tell jQuery not to set contentType上传文件要设置,告诉jqury不要做特殊的处理 success:function(arg,a1,a2){ console.log(arg); console.log(a1); console.log(a2); } }) } </script> </body> </html>
3.3 iframe实现上传
upload.html:
<body> <form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1"> <iframe id="ifm1" name="ifm1" style="display: none;"></iframe> <input type="file" name="fafafa" /> <input type="submit" onclick="iframeSubmit();" value="Form提交"/> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function iframeSubmit(){ $('#ifm1').load(function(){ var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); }) } </script> </body>
四、图片上传并能预览
先来一个点击提交才能预览图片的方式:
views.py:
def upload_file(request): username = request.POST.get('username') fafafa = request.FILES.get('fafafa') import os img_path = os.path.join('static/imgs/',fafafa.name) #指定图片的上传位置,就是将图片上传到static/imgs/目录下 with open(img_path,'wb') as f: for item in fafafa.chunks(): f.write(item) ret = {'code': True , 'data': img_path} import json return HttpResponse(json.dumps(ret))
upload.html :
<!DOCTYPE html> <html lang="en"> <head> </head> <body> <form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1"> <iframe id="ifm1" name="ifm1" style="display: none;"></iframe> <input type="file" name="fafafa" /> <input type="submit" onclick="iframeSubmit();" value="Form提交"/> </form> <div id="preview"></div> <script src="/static/jquery-1.12.4.js"></script> <script> function iframeSubmit(){ $('#ifm1').load(function(){ var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); console.log(obj,obj.data); $('#preview').empty(); //先清空 var imgTag = document.createElement('img'); //先创建个img标签 imgTag.src = "/" + obj.data; //给img标签增加一个src地址,因为抓到的obj.data前面少个/,所以要拼接一下。 $('#preview').append(imgTag); //添加一个imgTag标签 }) } </script> </body> </html>
测试一下:
再来一个只要上传图片不管提交不提交呢都会出现预览效果:
upload.html:
<!DOCTYPE html> <html lang="en"> <head> </head> <body> <form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1"> <iframe id="ifm1" name="ifm1" style="display: none;"></iframe> <input type="file" name="fafafa" onchange="changeUpalod();" /> <!--绑定一个onchange事件,只要状态改变就触发changeUpalod()--> <input type="submit" onclick="iframeSubmit();" value="Form提交"/> </form> <div id="preview"></div> <script src="/static/jquery-1.12.4.js"></script> <script> //只要选择完图片就触发下面的函数产生预览效果 function changeUpalod(){ $('#ifm1').load(function(){ var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); $('#preview').empty(); var imgTag = document.createElement('img'); imgTag.src = "/" + obj.data; $('#preview').append(imgTag); }); //$('#form1').submit(); //注意这里,如果有这里就不需要下面的提交按钮了,它就是会将整个form1表单提交了,里面又iframe,图片也就跟着提交上去了。 } function iframeSubmit(){ $('#ifm1').load(function(){ var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); console.log(obj,obj.data); $('#preview').empty(); var imgTag = document.createElement('img'); imgTag.src = "/" + obj.data; $('#preview').append(imgTag); }) } </script> </body> </html>
测试一下: