python flask简单文件上传下载实现
功能:用python+flask实现简单的文件上传下载,并简单过滤下文件名的“.”和“/”,同时对文件名进行通过uuid重命名,存到服务器上,并将原文件名、重命名等信息保存到db中,需要时从db查询出来还原即可PS:适合单服务器,不适用于K8S部署,下一篇文章将介绍通过ceph存储文件,适合K8S PVC持久化存储实现:一、在db中定义文件ORM模型:#app/db/orm.pyclas...
·
功能:用python+flask实现简单的文件上传下载,并简单过滤下文件名的“.”和“/”,同时对文件名进行通过uuid重命名,存到服务器上,并将原文件名、重命名等信息保存到db中,需要时从db查询出来还原即可
PS:简单实现,适合单服务器小附件上传,不适合大文件处理,也不适用于K8S部署,下一篇文章将介绍通过ceph存储文件,适合K8S PVC持久化存储
实现:
一、在db中定义文件ORM模型:
#app/db/orm.py
class Attachments(db.Model):
__tablename__ = 'attachments'
id = db.Column(db.String(64), primary_key=True)
file_name = db.Column(db.String(200), nullable=True)
file_path = db.Column(db.String(64), index=True, nullable=True)
uploader = db.Column(db.String(30))
upload_time = db.Column(db.DateTime, default=datetime.now())
project_num = db.Column(db.String(11))
def __init__(self, **kwargs):
super(Attachments, self).__init__(**kwargs)
if self.id is None:
self.id = str(uuid.uuid1()).replace('-', '')
__mapper_args__ = {
"order_by": project_num.desc()
}
def __repr__(self):
return '<Attachment %s>' % self.file_name
二、API接口视图类
#app/api/v1/projects/project.py
from flask import request
from flask_restplus import Resource
......
@api.route('/<string:project_num>/upload')
class UploadFile(Resource):
"""
上传立项附件的API
"""
@login_required
@api.doc('upload project attachments')
@api.marshal_with(model.project_attachment)
@api.response(return_code.Successful, 'upload success')
@api.response(return_code.InternalServerError, 'upload failed')
def post(self, project_num):
"""上传立项相关附件材料"""
file = request.files.get('file')
resp = business.upload_project_file(file, project_num)
return resp, return_code.Successful
@api.route('/downloads/<string:file_path>')
@api.param('file_path', '服务器上真实的文件名')
class DownloadFile(Resource):
"""
下载已上传的文件
"""
@login_required
@api.doc('get the upload file by path')
@api.response(return_code.Successful, 'success')
@api.response(return_code.NotFound, 'file not found')
def get(self, file_path):
"""下载已上传的文件"""
return business.download_file(file_path)
三、上传、下载业务逻辑实现
#app/api/v1/projects/business.py
......
def secure_filename(filename):
"""
过滤上传文件的文件名中的特殊字符
:param filename:
:return:
"""
file_first_name = filename.rsplit('.', 1)[0].lower()
return file_first_name.replace('.','').replace('/','') + '.' + filename.rsplit('.', 1)[1].lower()
def change_filename(filename):
"""
修改上传文件的文件名避免冲突以及恶意代码
:param filename:
:return:
"""
fileinfo = os.path.splitext(filename)
filename = datetime.now().strftime("%Y%m%d%H%M%S") + str(uuid.uuid4().hex) + fileinfo[-1]
return filename
def upload_project_file(file, project_num):
"""
上传立项附件材料
:return:
"""
if not file:
raise exceptions.MyHttpParameterException('No file part in request')
if file.filename == '':
raise exceptions.MyHttpParameterException('No selected file')
if allow_file(file.filename):
origin_file_name = secure_filename(file.filename)
filename = change_filename(origin_file_name)
basepath = os.path.abspath(os.getcwd()) # 当前文件所在工作目录
uploadpath = os.path.join(basepath, UPLOAD_PATH)
user = g.current_user
try:
if not os.path.exists(uploadpath):
os.makedirs(uploadpath)
file.save(os.path.join(uploadpath, filename))
# 并将文件信息写入数据库
attachment = Attachments(file_name=origin_file_name, file_path=filename, uploader=user.name, project_num=project_num)
db.session.add(attachment)
db.session.commit()
except Exception as e:
logger.error('upload failed --> {}'.format(str(e)))
raise exceptions.MyHttpServerError('upload failed, an error ocure on server -->{}'.format(str(e)))
# to do with this file
return attachment
else:
raise exceptions.MyHttpForbidden('No allowed file type')
def get_project_attachments(project_num):
"""
获取项目的所有附件信息
:param project_num:
:return:
"""
attachments = Attachments.query.filter_by(project_num=project_num).all()
return attachments
def download_file(file_name):
"""
根据服务器上真实的文件名下载附件
:param file_name:
:return:
"""
basepath = os.path.abspath(os.getcwd()) # 当前文件所在工作目录
uploadpath = os.path.join(basepath, UPLOAD_PATH)
if os.path.isfile(os.path.join(uploadpath, file_name)):
return send_from_directory(uploadpath, file_name, as_attachment=True)
raise exceptions.MyHttpNotFound('not found file')
更多推荐
已为社区贡献4条内容
所有评论(0)