这个暑假主要在搞Flask-RESTful实现的一个图片网站,就肯定少不了上传图片的部分
第一次干这样的事,的确很棘手
主要是pictures业务逻辑模块的编写
主要的实现就是
获取图片---检查图片文件---图片信息筛选---多对多关系的储存---对外API
思路似乎看着很简单,,,,,,但是,真的要看很多东西,很多细节
获取图片信息
可能是上传图片,也可能是更新图片
接收参数包括文件路径,图片描述,图片标签,图片ID(更新时用)
def put_or_upload_picture(files,despriction,tags,picture_id=None)
检查图片文件
检查文件类型并重命名
def verify_and_rename_pictures(files):
files=request.files['files']
filename = secure_filename(files.filename)
if not filename.rsplit('.',1)[1] in flask.current_app.config['ALLOWED_EXTENSIONS']:
return {'error':'只能上传图片'}
nowtime = datetime.now()
#重命名,format字符串格式化
filename = hashlib.md5('{0}_{1}'.format(filename,nowtime).encode("gb2312")).hexdigest()+"."+filename.rsplit('.',1)[1]
files.save(os.path.join(flask.current_app.config['UPLOAD_FOLDER'], filename))
return filename
from werkzeug.utils import secure_filename
这是检查文件的一个安全函数
来自官网的解释:假定 ../ 的数量是正确的,而您会将这串字符与 UPLOAD_FOLDER 所指定的路径相连接,那么这个用户就可能有能力修改服务器文件系统上的一个文件,而他不应该拥有这种权限
这个函数所做的事情就是将../注释掉
>>> secure_filename('../../../../home/username/.bashrc')
'home_username_.bashrc'
ALLOWED_EXTENSIONS,UPLOAD_FOLDER已经在config中配置,就是文字表面意思
#上传图片配置
UPLOAD_FOLDER = os.getcwd()+'/app/uploadpic/'
MAX_CONTENT_LENGTH = 16 * 1024 * 1024 #文件最大限制16M,仅需配置
ALLOWED_EXTENSIONS = set(['bmp','svg','png','jpg','jpeg','gif'])
关于重命名,重命名有什么用呢?
一方面个人感觉管理方便,另一方面防御攻击,其实简单的重命名也是可以暴力猜解的
图片信息筛选
这里tags可能是多个,一种方法可以在请求解析时设置tags传入 action='append'
parser.add_argument('tags', type=str, action='append')
个人感觉我使用的就比较麻烦了,用户传入示例"风景 人物 学校"
if tags:
for tag in tags.split(" "): #空格分隔
if models.Tags.query.filter_by(tag=tag.strip()).all():
首先split对字符串按照空格分隔
查询tags是否已经存在,不存在再上传
strip()用于移除字符串头尾指定的字符,默认为空格
多对多关系的储存
tags和pictures是设置为多对多关系
储存的思路和以前的文章里具体操作一样 多对多关系模型
具体代码如下
if tags:
for tag in tags.split(" "): #空格分隔
if models.Tags.query.filter_by(tag=tag.strip()).all():
tagadd = models.Tags.query.filter_by(tag=tag.strip()).all()
pictures.tags.append(tagadd)
else:
tagadd = models.Tags(tag=tag.strip())
pictures.tags.append(tagadd)
tags循环查询,append方式添加到pic.tags中
对外API
这部分有模板可循,delete和get没有贴出来
请求解析介绍
def post_put_parser():
"""
请求解析设置
"""
parse = reqparse.RequestParser()
parse.add_argument(
'despriction', type=str, location='json', required=True)
parse.add_argument(
'address', type=werkzeug.datastructures.FileStorage,location='files', required=True)
parse.add_argument(
'tags', type=str, location='json', required=True)
return parse
class PicturesAPI(Resource):
"""
上传POST图片的API
"""
@jwt_required()
@helpers.standardize_api_response
def post(self):
parse = post_put_parser()
args = parse.parse_args()
despriction,address,tags = args['despriction'], args['address'],args['tags']
return controllers.put_or_upload_picture(address,despriction,tags)
class PictureAPI(Resource):
"""
更新PUT图片的API
"""
@jwt_required()
@helpers.standardize_api_response
def put(self):
parse = post_put_parser()
parse.add_argument('picture_id', type=str, location='json', required=True)
args = parse.parse_args()
picture_id,despriction,address,tags = args['picture_id'],args['despriction'], args['address'],args['tags']
return controllers.put_or_upload_picture(address,despriction,tags,picture_id)
删除图片
def delete_picture(picture_id):
#根据图片id删除相应图片
picture = models.Picture.query.filter_by(id=picture_id).first()
if not picture:
return {'error': '没有此图片'}
try:
os.remove(os.path.join(flask.current_app.config['UPLOAD_FOLDER'],picture.address))
except OSError:
return {"error": u'文件不存在'}
db.session.delete(picture)
mit()
return {'deleted': '图片已删除'}