flask:上传图片以md5二级目录存储服务器并提供完整图片地址
1 flask基本配置
# coding=utf-8 import os import hashlib 将以下的配置写入配置文件settings.py中 UPLOAD_FOLDER = '/static/tmp/uploads' ALLOWED_EXTENSIONS = set(['bmp', 'png', 'jpg', 'jpeg', 'gif']) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SERVER_USER_TMP_UPLOADS = os.path.join(BASE_DIR, "static", "tmp", "uploads") SERVER_USER_UPLOADS = os.path.join(BASE_DIR, "static", "user", "uploads") FLASK_USER_UPLOADS = os.path.join("static", "user", "uploads") SERVER_ADDR = "http://47.xx.1.25"
2 用到的主要函数,主要逻辑在第三步
# 验证图片拓展名 def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS # 图片生成md5值作为唯一ID def md5_file(file_path): md5_obj = hashlib.md5() with open(file_path, 'rb') as file_obj: md5_obj.update(file_obj.read()) file_md5_id = md5_obj.hexdigest() return file_md5_id # 生成图片存储的二级目录和新的md5图片名 def md5_save_dir(img_id,filename): img_id = str(img_id) first_path = img_id[0:2] second_path = img_id[2:4] prefix = img_id suffix = filename.rsplit('.')[1] md5_filename = prefix + '.' + suffix relative_path = os.path.join(first_path,second_path) return relative_path,md5_filename
3 主要逻辑
# 上传处理的主要逻辑 @bp.route("/api/v1/upload", methods=['POST']) def upload(): if request.method == "POST": # 接收图先检验,如果图片存在并且是允许的文件类型 file = request.files['file'] if file and allowed_file(file.filename): filename = secure_filename(file.filename) # 比如图片名字:hello.jpg # 图片临时绝对路径,默认当前项目目录的static下,比如/data/www/hello/static/tmp/uploads absolute_path = os.path.join(SERVER_USER_TMP_UPLOADS, filename) #/data/www/hello/static/tmp/uploads/hello.jpg file.save(absolute_path) # 计算图片md5值作为图片ID返回,此处计算md5过程产生的时间差 md5_t1 = time.time() img_id = md5_file(absolute_path) md5_delta = (time.time() - md5_t1) * 1000 # 根据图片ID(即md5)返回图片前两节目录和最终md5名字,比如:615fa43bd047d1b189be52e35591d744 rela_path, md5_name = md5_save_dir(img_id, file.filename) # 比如:61/5f,615fa43bd047d1b189be52e35591d744.jpg # 创建md5的两级文件夹,比如/data/www/hello/static/user/uploads/61/5f md5_absolute_path = os.path.join(SERVER_USER_UPLOADS, rela_path) if not os.path.isdir(md5_absolute_path): os.makedirs(md5_absolute_path) # 在md5文件夹下面用图片另存为md5名字的图片 md5_name = secure_filename(md5_name) md5_absfile_path = os.path.join(md5_absolute_path, md5_name) shutil.move(absolute_path, md5_absfile_path) print("图片在服务器绝对路径", md5_absfile_path) # 比如:/data/www/hello/static/user/uploads/61/5f/615fa43bd047d1b189be52e35591d744.jpg md5_relative_path = os.path.join(FLASK_USER_UPLOADS, rela_path) md5_relfile_path = os.path.join(md5_relative_path, md5_name) print("图片在web访问时的静态文件路径", md5_relfile_path) # 比如:/static/user/uploads/61/5f/615fa43bd047d1b189be52e35591d744.jpg # 然后web访问静态资源时,由于nginx做了静态资源处理,会自动域名+相对地址即静态文件的地址 # 比如:http://xxx.xxxx.xxx/static/user/uploads/61/5f/615fa43bd047d1b189be52e35591d744.jpg full_img_path = os.path.join(SERVER_ADDR, md5_relfile_path) # 比如:http://xxx.xxxx.xxx/static/user/uploads/61/5f/615fa43bd047d1b189be52e35591d744.jpg
精简版:
@bp.route("/api/v1/upload", methods=['POST']) def upload(): if request.method == "POST": file = request.files['file'] if file and allowed_file(file.filename): filename = secure_filename(file.filename) absolute_path = os.path.join(SERVER_USER_TMP_UPLOADS, filename) file.save(absolute_path) img_id = md5_file(absolute_path) rela_path, md5_name = md5_save_dir(img_id, file.filename) md5_absolute_path = os.path.join(SERVER_USER_UPLOADS, rela_path) if not os.path.isdir(md5_absolute_path): os.makedirs(md5_absolute_path) md5_name = secure_filename(md5_name) md5_absfile_path = os.path.join(md5_absolute_path, md5_name) shutil.move(absolute_path, md5_absfile_path) md5_relative_path = os.path.join(FLASK_USER_UPLOADS, rela_path) md5_relfile_path = os.path.join(md5_relative_path, md5_name) full_img_path = os.path.join(SERVER_ADDR, md5_relfile_path) data={} data['id']=img_id data['img_url']=full_img_path return jsonify(data)