涉及知识点:
- file类型的input框,设置多选文件或者上传整个目录
- 第三方jquery库取cookie
- ajax批量上传文件,formData()取到form中的数据
前端库下载地址:https://www.bootcdn.cn/
参考:https://blog.csdn.net/leaves_story/article/details/80416853
需求:通过ajax实现目录下所有文件的上传
1.前端代码
使用ajax的目的:使页面在不刷新的基础上批量上传文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax大量文件上传</title>
<script src="/static/js/jquery3.4.1.js"></script>
<script src="/static/js/jquery.cookie.js"></script>
</head>
<body>
<form action="/test1/upload_dir/" enctype="multipart/form-data" method="post" id="formUploadDir">
{% csrf_token %}
<!-- webkitdirectory:设置目录上传,貌似仅支持chrome -->
<input type="file" name="files" id="uploadDir" webkitdirectory>
<button>form表单上传</button>
</form>
<input type="button" value="ajax提交" id="ajaxUploadDirBtn">
<!-- multiple:允许同时上传多个文件 -->
<p><input type="file" name="files" id="uoloadfiles" multiple></p>
</body>
<script>
$(function () {
$("#ajaxUploadDirBtn").click(function () {
// 构造表单对象,构造时传参必须传入form节点对象
// $("#formUploadDir")取到的是form对象的一个数组,然后通过索引取到对应form中的数据
var formData = new FormData($("#formUploadDir")[0]);
// 取到cookie中csrf的值,依赖第三方jquery库
var token = $.cookie("csrftoken");
// 判断上传的目录是否为空,非空时files对应目录中第一个文件的路劲
// C:\fakepath\desktop.ini:浏览器为了安全,不暴露客户端的完整文件路径
var files = $("#uploadDir").val();
if(files==""){
alert("请选择要上传的目录或该目录为空")
return
}
$.ajax({
url: '/test1/upload_dir/',
type: 'post',
data: formData,
headers: token, // django默认阻止post请求,带上csfr_token
async: false,
cache: false,
// 告诉jquery不用设置Content-Type请求头
contentType: false,
// 告诉jquery不用去处理发送的数据
processData: false,
success: function (resp) {
alert("OK")
},
error: function (resp) {
alert('error')
}
})
})
})
</script>
</html>
2.后端上传代码
form表单提交和ajax提交,后端逻辑是一样的
import os
from django.shortcuts import render, HttpResponse
UPLOAD_PATH = 'D:\\test1\\'
# Create your views here.
def files_upload(request):
if request.method == 'GET':
return render(request, 'filesupload.html')
elif request.is_ajax():
# 根据input框的name属性值取到文件对象
files = request.FILES.getlist('files')
for file in files:
# 获取文件名,文件对象的__str__属性返回的是文件名
file_name = str(file)
with open(os.path.join(UPLOAD_PATH, file_name), 'wb') as f:
# 分块写入,防止大文件卡死
for chunk in file.chunks(chunk_size=2014):
f.write(chunk)
return HttpResponse('ajaxOK')
3.后端下载FileResponse
HttpResponse有个很大的弊端,其工作原理是先读取文件,载入内存,然后再输出。如果下载文件很大,该方法会占用很多内存。对于下载大文件,Django更推荐StreamingHttpResponse和FileResponse方法,这两个方法将下载文件分批(Chunks)写入用户本地磁盘,先不将它们载入服务器内存。
def download_file(request):
id_ = request.POST.get('id')
file_obj = UploadFile.objects.get(id=id_)
filename = file_obj.file_name
# 文件将会自动关闭,所以不能使用with语句打开文件
fr = open(os.path.join(FILEDIR, filename), 'rb')
# 接受二进制内容
response = FileResponse(fr)
# 设置参数,使客户端直接下载到磁盘上
response['content_type'] = "application/octet-stream"
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
return response