Flask开发(十五)Flask数据交互 使用Flask上传文件
内容纲要
本篇导读:
- 上传文件简单使用
- 上传文件进阶
在Web开发时,经常需要实现文件上传的功能。可以以普通方式进行文件的上传,上传过程中一般要检查上传的文件格式时是否符合要求,文件保存时要注意绝对路径和相对路径问题。
使用Flask上传文件的简单实现
Flask文件上传比较简单,需要有一下三点要求:
- 一个<form>标签被标记有enctype=multipat/form-data,并且在里面包含一个<input type=file>标签。
- 服务端应用通过请求对象上的files字典访问文件。
- 使用文件的save()方法将文件永久地保存在文件系统上的某处。
from flask import Flask,render_template,request import os from os import path from werkzeug.utils import secure_filename
os.path方法下相关属性如下:
- os.path.sep:Windows下路径分隔符‘\’
- os.path.sep:linux下路径分隔符‘/’
- 根目录:os.path.curdir
- 父目录:os.path.abspath(path)
- 绝对路径:os.path.join()
在Windows下的路径分隔符和Linux下的路径分隔符是不一样的,当直接使用绝对路径时,跨平台会弹出No Such file or diretory的异常提示。
from werkzeug.utils import secure_filename:导入secure_filename方法,将中文文件名称传给secure_filename方法时所有的中文名都会被过滤掉,只剩下文件后缀名。
@app.route('/',methods=('GET','POST')) def hello_world(): if request.method == 'GET': return render_template('upload.html') else: f=request.files['file'] filename = secure_filename(f.filename) f.save(path.join('static/uploads',filename)) return '文件上传成功' if __name__ == '__main__': app.run(debug=True)
下面结合上面的阐述,给出一个文件上传的示例:
app.py文件的内容如下:
from flask import Flask,render_template,request from os import path from werkzeug.utils import secure_filename app = Flask(__name__) @app.route('/',methods=('GET','POST')) def hello_world(): if request.method == 'GET': return render_template('upload.html') else: f=request.files['file'] filename = secure_filename(f.filename) f.save(path.join('static/uploads',filename)) return '文件上传成功' if __name__ == '__main__': app.run(debug=True)
upload.html的文件内容如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> .div1{ height: 180px; width: 380px; border: 1px solid #8A8989; margin: 0 auto; } .input{ display: block; width: 250px; height: 30px; margin: 10px auto; } .button{ background: #2066c5; color: white; font-size: 18px; font-weight: bold; height: 30px; border-radius: 4px; } </style> </head> <body> <div class="div1"> <form action="" method="post" enctype="multipart/form-data"> <input type="file" name="file" class="input"> <input type="submit" value="上传" class="input button"> </form> </div> </body> </html>
运行上面程序之前,请先确保根目录下的static目录下已经创建好uploads目录,然后就可以运行本工程代码了。本工程可以实现上传任何文件,但是以中文命名的文件上传时,会出现中文名的丢失。
上传文件进阶
上面的示例代码中,实现了基本的文件上传功能,但是存在一些问题:
- 文件没有重新命名,多个用户可能会存在上传同名文件的问题;
- 没有实现文件目录的自动创建,如果网站部署时忘记创建文件保存目录,则会出现文件保存失败问题,影响用户体验;
- 文件上传时,没有进行必要的文件格式检验,用户可以直接将可执行文件上传到服务器上,影响到服务器的数据安全性。
改进app.py文件内容:
import time from flask import Flask,render_template,request import os from os import path from werkzeug.datastructures import CombinedMultiDict from werkzeug.utils import secure_filename, send_from_directory import platform from form import UploadForm app = Flask(__name__) if platform.system() == 'Windows': slash='\\' else: slash='/' UPLOAD_PATH = os.path.curdir+slash+'uploads'+slash @app.route('/',methods=('GET','POST')) def hello_world(): if request.method == 'GET': return render_template('upload.html') else: if not os.path.exists(UPLOAD_PATH): os.makedirs(UPLOAD_PATH) form = UploadForm(CombinedMultiDict([request.form,request.files])) if form.validate(): f = request.files['file'] filename = secure_filename(f.filename) ext = filename.rsplit('.',1)[1] unix_time = int(time.time()) new_filename = str(unix_time)+'.'+ext file_url=UPLOAD_PATH+new_filename f.save(path.join(UPLOAD_PATH,new_filename)) else: return '只支持jpg、png以及gif格式的文件!' return '文件上传成功' @app.route('/images/<filename>/',methods=('GET','POST')) def get_image(filename): dirpath = os.path.join(app.root_path,'uploads') # return send_from_directory(dirpath,filename,environ={'REQUEST_METHOD':'GET'},as_attachment=True) # 为下载方式 return send_from_directory(dirpath,filename,environ={'REQUEST_METHOD':'GET'}) #为浏览方式 if __name__ == '__main__': app.run(debug=True)
新建fom.py文件,内容如下:
from wtforms import Form,FileField from flask_wtf.file import FileRequired,FileAllowed class UploadForm(Form): file=FileField(validators=[FileRequired(),FileAllowed(['jpg','png','gif'])])
FileRequired用来验证文件上传是否为空。FileAllowed用来验证上传文件的后缀名。
效果如下:
阅读剩余
版权声明:
作者:雪落长安
链接:https://blog.wlbc321.cn/index.php/2021/05/27/flask15/
文章版权归作者所有,未经允许请勿转载。
THE END