Flask实现图片(文件)的(批量)上传、下载及示例代码

您所在的位置:网站首页 压缩专家软件可以一次上传多个吗 Flask实现图片(文件)的(批量)上传、下载及示例代码

Flask实现图片(文件)的(批量)上传、下载及示例代码

2023-11-03 09:55| 来源: 网络整理| 查看: 265

一、图片的单张上传(包括图片的尺寸压缩)

图片上传的基本思想大概是这样,前端用一个表单中type为file的input标签作为图片上传的前台发起上传,并以ajax把整个表单发送到后台,后台则是接收到图对象,加以处理,保存到服务器指定目录即可。首先先介绍下前台的代码,以及上传文件的form表单。

form表单如下:

from flask_wtf import FlaskForm from wtforms import FileField from app import label from flask_wtf.file import FileField, FileRequired, FileAllowed from config import ALLOWED_EXTENSIONS class ImgForm(FlaskForm): photo = FileField(validators=[FileAllowed(ALLOWED_EXTENSIONS, message=label('_allow_img', [str(ALLOWED_EXTENSIONS)]))])

其中的config 如下:

ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg'])

其中的label为如下:

def label(name, values=[], path=None): ''' 默认从app目录下的guide导入所需变量 name 导入的数据变量名 values 数据类型必须市列表,提示的动态内容 path 为导入的路径 name ''' path = ".".join(path.split(".")[:-1]) + ".guide:" if path else "app.guide:" msg = import_string(path + name) return msg.format(values) if len(values) else msg _allow_img = '''图片的格式只能{0[0]}'''

后台的视图函数则是实例化该ImgForm,传到前台,前台的html代码为:

{{ imgform.hidden_tag() }} 上传图片 {{ imgform.photo(class="upload") }}

hidden_tag()一定不要漏掉,不然后台将无法获取到我们传到后台的数据。js代码如下:

$('#img_file #photo').on('change',function(){ var imgform = new FormData(document.getElementById("img_file")); imgform.append ("key" , "value") $.ajax({ url:'{{ url_for("app.upload_img") }}', type:"POST", dataType:'json', data:imgform, cache: false, processData: false, contentType: false, success:function(response){ alert('上传成功') }, error:function(e){ alert('上传失败') } }) })

其中的imgform.append,则是给form对象添加我们想要传到后台的数据,比如你要传一个name为MuMu的数据到后台就可以这么写:

imgform.append ("name" , "MuMu");

flask后台接口:

from PIL import Image @app.route('/upload_img', methods=['POST']) def upload_img(): form = ImgForm() if form.validate(): file = request.files['photo'] MuMu = request.form.get('name') img = Image.open(file) img_w, img_h = img.size img_name_path = os.getcwd() + label('_img_name_path') img_name = get_line(img_name_path, 1) set_size(img, img_w, img_h, 1.0, img_name_path, img_name+'_L', '.png') set_size(img, img_w, img_h, 0.5, img_name_path, img_name+'_M', '.png') set_size(img, img_w, img_h, 0.2, img_name_path, img_name+'_S', '.png') imgL = img_name+'_L.png' imgM = img_name+'_M.png' imgS = img_name+'_S.png' add_img(imgL, MuMu) add_img(imgM, MuMu) add_img(imgS, MuMu) result = {'success':label('_update_succ')} else: result = form.errors return json.dumps(result)

其中set_size函数为图片处理函数,如下:

def set_size(im, imgw, imgh, size, path, name, Suffix): img_w, img_h = int(imgwsize), int(imghsize) img = im.resize((img_w, img_h), Image.ANTIALIAS) imgpath = path + name + Suffix img.save(imgpath) 二、图片的批量上传(包括图片的尺寸压缩)

图片的保存到制定目录跟单张的一样,唯一区别在于,批量上传是以压缩文件的形式上传,思路是先上传到制定目录,然后解压出来,再把里面的图片保存到制定目录,最后再移除压缩文件与解压出来的文件。前台代码跟上面的上传图片类似,就不再重复介绍。主要介绍一下上传压缩文件后的从图片图片处理过程。假设现在已经上传了压缩文件。后台处理接口如下:

@app.route('/upload/imgfile', methods=['POST']) def upload_imgfile(): form = FileForm() if form.validate(): file = request.files['name'] sku_path = '/app/product/csv/' uploadname = upload_file(sku_path, file, flag=False) file_list=[] imgs={} child_file = [] if uploadname: file_path = os.getcwd() + sku_path + uploadname if uploadname[-3:] == 'zip': filename=un_zip(file_path) elif uploadname[-3:] == 'tar': filename=un_tar(file_path) for i in os.walk(filename): file_list.append(i) for j in file_list: for k in file_list[1][1]: pathn = file_list[1][0] + '/' + k if pathn == j[0]: imgs[k]=j[2] for key in imgs: for img_l in imgs[key]: file = file_list[1][0]+'/'+key +'/'+img_l img = Image.open(file) img_w, img_h = img.size img_name_path = os.getcwd() + label('_img_name_path') img_name = get_line(img_name_path, 1) set_size(img, img_w, img_h, 1.0, img_name_path, img_name+'_L', '.png') set_size(img, img_w, img_h, 0.5, img_name_path, img_name+'_M', '.png') set_size(img, img_w, img_h, 0.2, img_name_path, img_name+'_S', '.png') imgL = img_name+'_L.png' imgM = img_name+'_M.png' imgS = img_name+'_S.png' add_img(imgL, img_l[:-4]) add_img(imgM, img_l[:-4]) add_img(imgS, img_l[:-4]) remove_file(sku_path, filename[:-1], flag=False) remove_file(sku_path, uploadname) result = {'success':label('_update_succ')} else: result = form.errors return json.dumps(result)

其中un_zip、un_tar解压函数以及文件移除函数如下,需要注意的是移除单个文件只需要remove即可,而如果想移除一个文件夹则需要用rmtree方法才能移除,详情如下:

def remove_file(path, filename, flag=True): ''' 删除文件 判断文件是否存在,存在则删除 ''' path = BASE_PATH + path filename = os.path.join(path, filename) if os.path.exists(filename): if flag: os.remove(filename) else: shutil.rmtree(filename) def upload_file(path, file, flag=True): ''' 上传文件 ''' if flag: name = int(time.time()*1000) else: name = file.filename if file: path = BASE_PATH + path file.save(os.path.join(path, str(name))) return name def un_zip(file_name): """unzip zip file""" zip_file = zipfile.ZipFile(file_name) if os.path.isdir(file_name[:-4] + "files"): pass else: os.mkdir(file_name[:-4] + "files") for names in zip_file.namelist(): zip_file.extract(names, file_name[:-4] + "files/") zip_file.close() return (file_name[:-4] + "files/") def un_tar(file_name): tar = tarfile.open(file_name) names = tar.getnames() if os.path.isdir(file_name[:-4] + "files"): pass else: os.mkdir(file_name[:-4] + "files") for name in names: tar.extract(name, file_name[:-4] + "files/") tar.close() return (file_name[:-4] + "files/")

其中的get_line函数则是一个操作txt文件的函数,我们事先把图片名放在txt中,上传一张图片就从文件中提取出一行图片名,并删除一行,若删除图片则写回txt中,这是个一个良好的解决命名冲突的问题。代码如下:

def get_line(file, del_line): with open(file, 'r') as old_file: with open(file, 'r+') as new_file: current_line = 0 # 定位到需要删除的行 while current_line ; (del_line - 1): old_file.readline() current_line += 1 # 当前光标在被删除行的行首,记录该位置 seek_point = old_file.tell() # 设置光标位置 new_file.seek(seek_point, 0) # 读需要删除的行,光标移到下一行行首 getline = old_file.readline() # 被删除行的下一行读给 next_line next_line = old_file.readline() # 连续覆盖剩余行,后面所有行上移一行 while next_line: new_file.write(next_line) next_line = old_file.readline() # 写完最后一行后截断文件,因为删除操作,文件整体少了一行,原文件最后一行需要去掉 new_file.truncate() return (getline.strip()) 三、图片的单张下载

我是采用h5中a标签的新属性,即a标签中的href为图片的绝对路径,增加一个download属性即为图片下载,且download值则是下载后图片的名称。(有一个不足即使兼容性不怎么好,目前仅支持谷歌浏览器以及火狐浏览器),例子如下:

下载 四、图片的批量下载

批量下载的本质也是跟单张的一样,只不过要点击批量下载,要用js遍历模拟点击a标签实现多张下载,js如下:

$(function(){ $('#panel_head').height('45px') $('input[name="checkbtn"]').each(function(){ $(this).on('click',function(){ chkval = [] upsku = [] if($("input[name='checkbtn']:checked").length 0 ){ $('#batch_download').removeClass('hide'); }else{ $('#batch_download').addClass('hide') } for(var j=0;j chkval.push($("input[name='checkbtn']:checked")[j].value) upsku.push($("input[name='checkbtn']:checked")[j].getAttribute("data-sku")) } } }) }) var btn = document.getElementById('batch_download'); function download(name, href) { var a = document.createElement("a"), //创建a标签 e = document.createEvent("MouseEvents"); //创建鼠标事件对象 e.initEvent("click", false, false); //初始化事件对象 a.href = href; //设置下载地址 a.download = name; //设置下载文件名 a.dispatchEvent(e); //给指定的元素,执行事件click事件 } //给多文件下载按钮添加点击事件 btn.onclick = function(){ for (var index = 0; index ; chkval.length; index++) { download(upsku[index], chkval[index]); } } }) 附加:批量文件上传处理并下载

如果想实现多文件同时上传(例如:csv、xlsx、xls等),前端的表单需要加个属性:enctype="multipart/form-data"才能实现文件多选,且选择多文件上传的时候需要按住ctrl,按住shift则是把点选当前的文件以及前面的文件全部选定,然后点击打开即可完成文件选定。前端代码如下:

{% from "macros/upload_form.html" import modal %} 多文件上传 上传待处理数据 {{ modal(csvform, mymodal="upload_data", action='', enctype="multipart/form-data", id='upload_form', fade="modal fade", displays="display: none", title='上传待处理数据') }}

其中引用到的宏模板如下:

{# 开始表单字段 #} {% macro modal_form_field(field) %} {%- if field.type != 'SubmitField' %} {%- if field.type == 'FileField' %} {{ field(class="form-control", placeholder=field.label.text, multiple="multiple") }} {% else %} {{ field(class="form-control", placeholder=field.label.text) }} {% endif -%} {% endif -%} {% endmacro %} {# 结束表单字段 #} {% macro modal(form, mymodal = "myModal_1", title = "", action="", method="post", role="form", form_type="basic", enctype=None, button_map={}, id="", fade="modal fade", displays="display: none", closeWin="", novalidate=False) %} {%- set _enctype = [] %} {%- if enctype is none -%} {%- for field in form %} {%- if field.type == 'FileField' %} {%- set _ = _enctype.append('multipart/form-data') -%} {%- endif %} {%- endfor %} {%- else %} {% set _ = _enctype.append(enctype) %} {%- endif %}


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3