zoukankan      html  css  js  c++  java
  • 如何实现图片上传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:完整代码

  • 相关阅读:
    java 环境变量配置
    框架分成介绍
    Net 新特性
    一 设计模式六大原则
    web api 配置
    Visual Studio检查内存泄露方法
    深度比较对象的不同
    reportview 安装使用
    Nuget 常用命令
    freeswitch学习笔记
  • 原文地址:https://www.cnblogs.com/bay1/p/10982477.html
Copyright © 2011-2022 走看看