如何实现图片上传API

这个暑假主要在搞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)
    db.session.commit()
    return {'deleted': '图片已删除'}

PS:完整代码

原文地址:https://www.cnblogs.com/bay1/p/10982477.html