如何实现图片上传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:完整代码

posted @   bay1  阅读(1159)  评论(0编辑  收藏  举报
编辑推荐:
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
阅读排行:
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 2025成都.NET开发者Connect圆满结束
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 用一种新的分类方法梳理设计模式的脉络
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
bay1
主题色彩
点击右上角即可分享
微信分享提示