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

news2024/9/21 4:38:03

前言

后端返回的是文件地址,并不是文件流或base64编码字符串,而修改数据的接口又只接受文件。
本篇文章主要是基于累加文件上传介绍的。
添加上传文件文章链接:https://blog.csdn.net/qq_43030934/article/details/128726549?spm=1001.2014.3001.5501

一.实现思路

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

二.实现效果

回显的文件可以下载和同步服务器删除文件
1.编辑回显页面
在这里插入图片描述
2.再次选择追加文件
在这里插入图片描述

三.代码实现

该项目用的是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) + "&nbsp;&nbsp;&nbsp;&nbsp;<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 "&nbsp;&nbsp;&nbsp;&nbsp;<a class='fa fa-download' href='/file/teams_data_structure_file_download/" + file_id + "'></a>"
}

function getDeleteFileIcon(file_id) {
    return "&nbsp;&nbsp;&nbsp;&nbsp;<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 '&nbsp;&nbsp;(' + sizestr.substring(0, len) + sizestr.substr(len + 3, 2) + ')';
    }
    return '&nbsp;&nbsp;(' + 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!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/172348.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jmeter 压测java代码

一、背景 直接压测、调用java工程中的方法。&#xff08;没有http等的入口&#xff09; 二、java项目改造 一个java项目&#xff0c;想要压测其中的几个方法。我们需要在该工程中&#xff0c;添加一个压测入口的类&#xff0c; 这个类必须继承或者实现jmeter提供的接口/类。…

C语言萌新如何使用scanf函数?

&#x1f40e;作者的话 如果你搜索输入输出函数&#xff0c;那么你会看到输入输出流、Turbo标准库、标准输出端、stdout什么什么乱七八糟的&#xff0c;作为一个萌新&#xff0c;哪懂这些&#xff1f; 本文介绍萌新在前期的学习中&#xff0c;常用的输入输出函数及其功能~ 跳…

HTML5+CSS3小实例:炫彩的发光字特效

前言&#xff1a; 今天我们向大家精选了一款HTML5CSS3文字特效&#xff0c;文字特效有超酷的动画类型&#xff0c;不多说&#xff0c;一起来看看。 描述&#xff1a; 这款文字特效既有倒影的效果&#xff0c;又有随机的颜色&#xff0c;看起来非常的炫酷。全文基于 HTML5CSS3 完…

log4j.properties自定义日志配置

一、通用的写法log4j.properties# 设置root logger等级为ALL&#xff0c;且appender有A1和FILE log4j.rootLoggerALL, A1,A3#设置com.example.test logger log4j.logger.com.example.testDEBUG,A1,A3 # 取消继承父类 log4j.additivity.com.example.testfalse# 设置个控制台输出…

即时通讯开发之TCP 连接的建立与中止

TCP 是一个面向连接的协议,所以在连接双方发送数据之前,都需要首先建立一条连接。这和前面讲到的协议完全不同。前面讲的所有协议都只是发送数据 而已,大多数都不关心发送的数据是不是送到,UDP 尤其明显,从编程的角度来说,UDP 编程也要简单 的多----UDP 都不用考虑数据分片。 书…

Ubuntu下源码编译VirtualBox一 —— 源码下载

VirtualBox想必大家都不陌生&#xff0c;做Linux开发的尤其是嵌入式Linux开发的人应该基本都知道或玩过VMware和VirtualBox。但通常都是为了在Windows电脑上能够使用Linux环境、即在Windows环境下通过下载可执行文件安装的VirtualBox。本文介绍在Linux环境&#xff08;Ubuntu 2…

系分 - 论文 - 总览知识点

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录系分 - 论文 - 总览往年论文一览论文考点考试时间考试过程论文技巧论文写作论文扣分与加分系分 - 论文 - 总览 往年论文一览 一般情况下&#xff0c;往下数5、6年的题目出题形式&#xff0c;具有参考意义…

痞子衡嵌入式:盘点国内Cortex-M内核MCU厂商高主频产品(2023)

大家好&#xff0c;我是痞子衡&#xff0c;是正经搞技术的痞子。今天痞子衡给大家介绍的是国内Cortex-M内核MCU厂商高主频产品。 在 2021 年初痞子衡写了篇 《盘点国内Cortex-M内核MCU厂商高性能产品》&#xff0c;搜罗了当时市面上主频不低于 96MHz 的 CM 核国产 MCU。如今过去…

LSTM MultiheadAttention 输入维度

最近遇到点问题&#xff0c;对于模块的输入矩阵的维度搞不清楚&#xff0c;这里在学习一下&#xff0c;记录下来&#xff0c;方便以后查阅。 LSTM & Attention 输入维度LSTM记忆单元门控机制LSTM结构LSTM的计算过程遗忘门输入门更新记忆单元输出门LSTM单元的pytorch实现Pyt…

Spring Security in Action 第七章 配置授权:限制访问

本专栏将从基础开始&#xff0c;循序渐进&#xff0c;以实战为线索&#xff0c;逐步深入SpringSecurity相关知识相关知识&#xff0c;打造完整的SpringSecurity学习步骤&#xff0c;提升工程化编码能力和思维能力&#xff0c;写出高质量代码。希望大家都能够从中有所收获&#…

[leetcode 72] 编辑距离

题目 题目&#xff1a;https://leetcode.cn/problems/edit-distance/description/ 类似题目&#xff1a;[leetcode 583] 两个字符串的删除操作 解法 动态规划 这题应该是字符串dp的终极形态了吧&#x1f923;&#xff0c;不看答案完全不会…看了答案发现原来还是dp… 以例题…

未来的竞争是认知和执行力的竞争,只有认知高,强执行才能赚钱

之前很火的一句话是&#xff1a;你永远赚不到认知范围之外的钱所以只有持续不断地提升认知才能持续成长&#xff0c;持续提升&#xff0c;持续赚钱。未来的竞争从另一方面来说也是认知的竞争。不同的认知对待同一事物、信息有不同的理解&#xff1b;不同的认知对待同一事物、信…

固高科技在创业板提交注册:业绩开始下滑,实控人均为“学院派”

近日&#xff0c;固高科技股份有限公司&#xff08;下称“固高科技”&#xff09;在深圳证券交易所创业板递交注册。据贝多财经了解&#xff0c;固高科技于2021年12月在创业板递交上市申请&#xff0c;2022年8月17日获得上市委会议通过。 本次冲刺创业板上市&#xff0c;固高科…

【一道面试题】说一下Synchronized?

说一下Synchronized&#xff1f; Synchronized锁是Java中为了解决线程安全问题的一种方式&#xff0c;是一种悲观锁Synchronized可以用来修饰方法或者以代码块&#xff0c;用来保证线程执行方法或代码块时的原子性Java中任何一个类的对象都可以用来作为锁对象&#xff0c;但是…

docker-15-镜像Ubuntu20.04中安装python3.9

1 拉取并运行镜像 从docker hub 拉取镜像&#xff0c;以ubuntu20.04为例&#xff1a; docker pull ubuntu:20.04 docker run -it ubuntu:20.04 /bin/bash发现命令行变为root1234abcd5678:&#xff0c;这样就是进入docker容器里了。以下是docker常用的命令&#xff1a; # 以…

8086到80386汇编数据传送指令的扩展

80386及以上汇编的数据传送指令如下&#xff1b; MOV 传送字或字节. MOVSX 先符号扩展,再传送. MOVZX 先零扩展,再传送. PUSH 把字压入堆栈. POP 把字弹出堆栈. PUSHA 把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈. POPA 把DI,SI,BP,SP,BX,DX,CX,A…

人大金仓数据库KSQL常用命令

第三章KSQL常用命令 登陆前显示ksql的帮助命令 Ksql --help 列出所有的SQL命令清单 test# \h 列出某个SQL命令语法大纲 \h <sql命令> 如&#xff1a;\h delect 查看ksql元命令的帮助 ..... 查看数据库列表 显示当前连接的数据库和登录用户 \c 显示当前test数据库的…

数学和统计方法

平均数&#xff0c;加权平均数&#xff0c;中位数&#xff0c;众数 1、平均数&#xff1a;所有数加在一起求平均 2、中位数&#xff1a;对于有限的数集&#xff0c;可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个&#xff0c;通常取最中间的 …

Spring Boot学习篇(十一)

Spring Boot学习篇(十一) shiro安全框架使用篇(三) 1.shiro过滤地址配置(部分地址必须要登录才能访问) 1.1 在controll包下创建CRUDController类(用于提供地址进行测试),其内容如下所示 package com.zlz.controller;import org.springframework.stereotype.Controller; imp…

回顾一次后台从war包启动到jar包启动的改造

一、背景描述 1.项目情况 有个项目后台一开始是war包部署到tomcat中部署的 配置文件放在项目中 考虑到这种部署方式相对spring boot项目内置tomcat部署不太便捷&#xff0c;配置也没有独立出来&#xff0c;考虑将原来的spring mvc项目稍微改造为spring boot项目。 2.要求 1&am…