添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接


前言

后端返回的是文件地址,并不是文件流或base64编码字符串,而修改数据的接口又只接受文件。
本篇文章主要是基于累加文件上传介绍的。

一.实现思路

通过文件地址URL,将所指文件转为File文件对象

二.实现效果

回显的文件可以下载和同步服务器删除文件

1.编辑回显页面

前端js实现多次添加累加文件上传和选择删除(django+js)- 编辑回显文件并上传 (二)_Data


2.再次选择追加文件

前端js实现多次添加累加文件上传和选择删除(django+js)- 编辑回显文件并上传 (二)_前端_02

三.代码实现

该项目用的是django+js,前端部分基本都差不多,废话不多说,直接上代码吧。
这里贴主要的代码,如有问题可评论或私信。

1.html部分

form表单

{% block main %}
<!--根据自己项目目录路径引入自定义上传的组件的样式fileUpload.css文件-->
<link href="../../../static/public/css/fileUpload.css" rel="stylesheet"/>
...
<form id="dataStructureForm" method="post" class="container">

...
<!--add attachment-->
<div class="form-group">
<label class="font-weight-bold">Add attachments:</label>
<input class="choose-file-clip" type="file" id="selectFile" name="uploadFileBase" multiple="multiple">
<label for="selectFile" class="choose-file"><i class="fa fa-paperclip"></i> Choose File</label>
<div id="showFileName" class="upfile-list-mes"></div>
<span class="form-text text-muted">所有文件大小不超过50M。</span>
</div>
...
</form>
...
{% endblock %}

<!-- 此处为django模板加载js的写法 -->
{% block script %}
<script src="../../../static/pages/xxxxxxxxxxxx/xxxxxxxxx/editDataStructure.js"
type="text/javascript"></script>
{% endblock %}

自定义上传的组件的样式​ ​fileUpload.css​ ​文件

.choose-file-clip {
position: absolute;
clip: rect(0, 0, 0, 0);
}

.choose-file {
padding: 5px 20px;
font-size: larger;
background: #2ECA8B;
border-radius: 4px;
color: white;
cursor: pointer;
}

.upfile-list-mes {
color: #00bfff;
}

.icon-remove {
cursor: pointer;
color: #FD5373;
font-size: medium;
}

.file-name {
/*color: #00bfff;*/
color: #161C2D;
font-size: medium;
margin: 0;
}

2.js部分

2.1 关键代码

下面是前端提交form表单数据(包含文件)到后台的js,也就是django模板加载的​ ​editDataStructure.js​

var formData = new FormData($("#dataStructureForm")[0]);
if (fileLists.length > 0) {
var fileSize = 0
for (let i = 0; i < fileLists.length; i++) {
fileSize += fileLists[i].size
if (fileSize > 50 * 1024 * 1024) {
console.log('file size:', sizeToStr(fileSize))
$.messager.alert("提示", '所有文件大小不能超过50M!', "warning");
return
}
}
$(fileLists).each(function (i, e) {
console.log(e)
formData.append('uploadFile', e)
})
}
submit(formData)

2.2 全部代码

var fileLists = [];
var fileNameList = []
// 选择文件
$("#selectFile").on('change', function (event) {
let _files = this.files;
// console.log(_files[0])
_files = Array.from(_files); //将伪数组专为真数组修改
for (let i = 0; i < _files.length; i++) {
// 文件去重处理
if (fileNameList.indexOf(_files[i].name) === -1) {
fileLists.push(_files[i]);
fileNameList.push(_files[i].name)
// let html = "<p class='file-name'>" + _files[i].name + sizeToStr(_files[i].size) + "    <span class='icon-remove'><i class='fa fa-trash'></i></span></p>"
let html = "<p class='file-name'>" + _files[i].name + sizeToStr(_files[i].size) + getDeleteFileIcon(_files[i].id)
$('.upfile-list-mes').append(html);
}
}
})

$(function () {
var _files = MyViewVar.initialPreviewData
for (let i = 0; i < _files.length; i++) {
// 文件去重处理
if (fileNameList.indexOf(_files[i].name) === -1) {
addFile2FileLists(_files[i])
}
}
console.log(fileLists)
})

function addFile2FileLists(_files) {
var blob = null;
var xhr = new XMLHttpRequest();
xhr.open("GET", _files.url);
xhr.setRequestHeader("Content-type", "charset=utf-8");
xhr.responseType = "blob";
// 加载时处理
xhr.onload = () => {
// 获取返回结果
blob = xhr.response;
let file = new File([blob], _files.name, {type: _files.type});
// console.log('file==', file)
fileLists.push(file);
fileNameList.push(_files.name)
let html = "<p class='file-name'>" + _files.name + sizeToStr(_files.size) + downloadFile(_files.id) + getDeleteFileIcon(_files.id)
$('.upfile-list-mes').append(html);
};
// 发送
xhr.send();
}

function downloadFile(file_id) {
// console.log(file_id)
return "    <a class='fa fa-download' href='/file/teams_data_structure_file_download/" + file_id + "'></a>"
}

function getDeleteFileIcon(file_id) {
return "    <span οnclick='deleteFile(" + file_id + ", this)' class='icon-remove'><i class='fa fa-trash'></i></span></p>"
}

function deleteFile(file_id, e) {
console.log(file_id)
if (file_id) {
$.messager.confirm({
title: '提示', msg: '移除文件将会同步服务器删除文件!', fn: function (r) {
if (r) {
$.ajax({
url: server_url + '/file/del_teams_file_by_id/' + file_id + '/',
method: 'GET',
processData: false,
contentType: false,
cache: false,
success: function (data) {
console.log("data:" + data);
console.log("data:" + data.status);
if (data.status === 200) {
let ind = $(e).parent().index();
console.log(fileNameList[ind])
$(e).parent().remove();
fileLists.splice(ind, 1);
fileNameList.splice(ind, 1);
console.log(fileLists)
console.log("data:" + data.msg);
$.messager.alert({title: '提示', msg: data.msg, icon: 'info'});
return
}
console.log(data)
$.messager.alert({title: '提示', msg: data.msg, icon: 'warning'});
},
//请求失败,包含具体的错误信息
error: function (data) {
console.log('error' + data.msg);
$.messager.alert({title: '提示', msg: '请求服务错误或当前网络不佳!', icon: 'warning', top: 200});
}
});
}
}
});
} else {
let ind = $(e).parent().index();
console.log(fileNameList[ind])
$(e).parent().remove();
fileLists.splice(ind, 1);
fileNameList.splice(ind, 1);
console.log(fileLists)
}
}

function sizeToStr(size) {
var data = "";
if (size < 0.1 * 1024) { //如果小于0.1KB转化成B
data = size.toFixed(2) + "B";
} else if (size < 0.1 * 1024 * 1024) { //如果小于0.1MB转化成KB
data = (size / 1024).toFixed(2) + "KB";
} else if (size < 0.1 * 1024 * 1024 * 1024) { //如果小于0.1GB转化成MB
data = (size / (1024 * 1024)).toFixed(2) + "MB";
} else { //其他转化成GB
data = (size / (1024 * 1024 * 1024)).toFixed(2) + "GB";
}
var sizestr = data + "";
var len = sizestr.indexOf("\.");
var dec = sizestr.substr(len + 1, 2);
if (dec === "00") { //当小数点后为00时 去掉小数部分
return '  (' + sizestr.substring(0, len) + sizestr.substr(len + 3, 2) + ')';
}
return '  (' + sizestr + ')';
}

// 删除文件
// $(document).on('click', '.icon-remove', function (event) {
// let ind = $(this).parent().index();
// $(this).parent().remove();
// fileLists.splice(ind, 1);
// fileNameList.splice(ind, 1);
// console.log(fileLists)
// });

function SubmitEditForm() {
var submitbtn1 = document.getElementById("SubmitTop");
var submitbtn2 = document.getElementById("SubmitBottom");
var title = document.getElementById("id_title").value;
var full_name = document.getElementById("id_full_name").value;
var knowledge_category = document.getElementById("id_knowledge_category").value;
var team = document.getElementById("id_team").value;
console.log(title, full_name, knowledge_category, team)
//确认必选项是否都已填
if (title === '' || full_name === '' || knowledge_category === '' || team === '') {
submitbtn2.disabled = false;
submitbtn1.disabled = false;
$.messager.alert("提示", 'Must input all items with * !', "warning");
return false;
}
var formData = new FormData($("#dataStructureForm")[0]);
// $("#uploadFileId").fileinput("upload"); // 单独上传文件接口
if (fileLists.length > 0) {
var fileSize = 0
// console.log(fileLists)
for (let i = 0; i < fileLists.length; i++) {
fileSize += fileLists[i].size
// console.log(sizeToStr(fileSize))
if (fileSize > 50 * 1024 * 1024) {
console.log('file size:', sizeToStr(fileSize))
$.messager.alert("提示", '所有文件大小不能超过50M!', "warning");
return
}
}
$(fileLists).each(function (i, e) {
console.log(e)
formData.append('uploadFile', e)
})
}
console.log(fileLists)
submit(formData)
}

function submit(formData) {
// var form = document.forms[0];
console.log(formData.data)
// var jsonData = JSON.stringify(formData);
var submitbtn1 = document.getElementById("SubmitTop");
var submitbtn2 = document.getElementById("SubmitBottom");
submitbtn2.disabled = true;
submitbtn1.disabled = true;
submitbtn1.value = "loading...";
submitbtn2.value = "loading...";
var id = $('#obj_id').val()
console.log(id)
$.ajax({
url: server_url + '/teams/data_structure_detail/' + id + '/',
method: 'PUT',
data: formData,
dataType: "json",
processData: false,
contentType: false,
cache: false,
success: function (data) {
console.log("data:" + data);
console.log("data:" + data.res);
if (data.status === 200) {
$.messager.alert("提示", data.msg, "info");
console.log("data:" + data.msg);
window.setTimeout("window.location=server_url+'/teams/data_structure'", 500);
return;
}
submitbtn2.disabled = false;
submitbtn1.disabled = false;
submitbtn1.value = "Submit";
submitbtn2.value = "Submit";
console.log(data)
$.messager.alert("提示", data.msg, "info");
},
//请求失败,包含具体的错误信息
error: function (data) {
console.log(data.msg);
}
});
}

3. django后端

附上django后台处理上传文件的接口代码,仅供参考,这里用的是序列化器写的(序列化器的使用在本人的主页也有相关的博文介绍)。
接口​​ ​url​

urlpatterns = [
path('data_structure_detail/<int:id>/', DataStructureDetailView.as_view(), name='data_structure_detail'),
]

视图函数​ ​view.py​

class DataStructureDetailView(LoginRequiredJSONMixin, APIView):
def get(self, request, id):
ds = get_object_or_404(DataStructure, pk=id)
s = DataStructureSerializer(ds)
context = s.data
context['teams'] = [i for i in Team.objects.all() if i.name != context['team']['name']]
context['knowledge_categories'] = [i for i in KnowledgeCategory.objects.all() if
i.name != context['knowledge_category']['name']]
initialPreviewData = get_attachments_detail(ds)
context['initialPreviewData'] = initialPreviewData
context['user'] = ds.user
# print(context)
return render(request, 'teams/data_structure/edit_data_structure.html', context)

@transaction.atomic
def put(self, request, id):
# print(request.data)
ds = get_object_or_404(DataStructure, pk=id)
old_ds = copy.copy(ds)
s = EditDataStructureSerializer(instance=ds, data=request.data)
if s.is_valid():
new_ds = s.save()
# handle file
files_obj = request.FILES.getlist('uploadFile')
if files_obj:
handle_update_files(request, files_obj, new_ds, TeamFileSerializer)
# 变更差异信息
# old_ds_dic = model_to_dict(old_ds)
# new_ds_dic = model_to_dict(new_ds)
# diff = old_ds_dic.keys() & new_ds_dic
# diff_vals = [(k + ': from ' + str(old_ds_dic[k]) + ' to ' + str(new_ds_dic[k])) for k in diff if
# old_ds_dic[k] != new_ds_dic[k]]
# print(diff_vals)
return api_success('信息保存成功!Data loading')
return api_bad_request('数据表单验证失败,无法保存!')

def delete(self, request, id):
# print(request, id)
ds = get_object_or_404(DataStructure, pk=id)
res = delete_data(ds)
if res:
return api_success(res)
return api_bad_request('数据删除失败!')

ok,至此,文件的编辑回显并可以累加文件上传的介绍完成,若是该文对你有帮助,还望可以点赞收藏加关注哦!
此外,如果你有更好的编辑回显并可以累加上传的方法,还请留言上链接,博主也想继续学习,优化改善代码,提升效率!3Q!