【Python】如何实现图片上传和预览功能

879人浏览 / 0人评论 / 添加收藏

在使用Web表单时,经常会使用到上传文件功能,request.files对象可以获取与表单相关的数据。

项目的目录结构如下:

首先定义一个路由函数upload()用于上传图片,然后提交上传的图片,在另一个路由函数uploaded_file()中显示图片内容,具体操作步骤如下

① 在"templates"目录下创建文件上传模板upload.html,代码如下所示。

<!--upload.html-->
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>上传图片</title>
</head>
<body>
   <!--form表单中设置enctype="multipart/form-data",用于上传文件-->
   <form action="" method="post" enctype="multipart/form-data">
       <div>
           <label for="avatar">上传图片</label>
           <input type="file" id="avatar" name="avatar" value="">
       </div>
       <button type="submit">提交</button>
   </form>
</body>
</html>

② 创建一个run.py文件,在该文件中编写upload()路由函数,当接受GET请求时,显示模板文件内容;当接受POST请求时,上传图片

代码如下所示:

@app.route('/upload',methods=['GET','POST'])
def upload():
   """
   头像上传表单页面
   :return:
   """
   if request.method == 'POST':
       # 接受头像字段
       avatar = request.files['avatar']
       # 判断文件是否上传,已经上传文件类型是否正确
       if avatar and allowed_file(avatar.filename):
           # 生成一个随机文件名
           filename = random_file(avatar.filename)
           # 保存文件
           avatar.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
           return redirect(url_for('uploaded_file',filename=filename))

   return render_template('upload.html')

上述代码中,使用request.files['avatar']接收表单中name='avatar'的字段值,然后检测用户是否上传了图片,并且使用allowed_file()函数检测上传的文件类型是否满足设定的要求

allowed_file()函数代码如下所示。

ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])

def allowed_file(filename):
   """
   判断上传文件类型是否允许
   :param filename: 文件名
   :return: 布尔值True或False
   """
   return '.' in filename and \
          filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

接下来使用random_file()函数为上传的文件重新创建一个随机的不重复的文件名,通过使用uuid.uuid4()生产处一个随机的几乎不可能重复的文件名,然后拼接一个完整的路径,代码如下所示。

import uuid

def random_file(filename):
   """
   生成随机文件
   :param filename: 文件名
   :return: 随机文件名
   """
   # 获取文件后缀
   ext = os.path.splitext(filename)[1]
   # 使用uuid生成随机字符
   new_filename = uuid.uuid4().hex+ext
   return new_filename

准备工作完成后,最后调用avartar.save()方法将图片存储到相应的路径下

③ 在run.py文件中创建uploaded_file()路由函数,显示图片内容,代码如下所示

@app.route('/uploads/<filename>')
def uploaded_file(filename):
   """
   显示上传头像
   :param filename: 文件名
   :return: 真实文件路径
   """
   return send_from_directory(app.config['UPLOAD_FOLDER'],filename)

send_from_directory()函数用于显示静态资源文件

上述run.py文件完整代码如下所示

# run.py
import os
import uuid
from flask import send_from_directory
from flask import Flask, request, render_template, redirect, url_for

app = Flask(__name__)
UPLOAD_FOLDER = os.path.join(app.root_path, 'uploads')
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER


def allowed_file(filename):
   """
   判断上传文件类型是否允许
   :param filename: 文件名
   :return: 布尔值True或False
   """
   return '.' in filename and \
          filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS


def random_file(filename):
   """
   生成随机文件
   :param filename: 文件名
   :return: 随机文件名
   """
   # 获取文件后缀
   ext = os.path.splitext(filename)[1]
   # 使用uuid生成随机字符
   new_filename = uuid.uuid4().hex+ext
   return new_filename


@app.route('/upload', methods=['GET', 'POST'])
def upload():
   """
   头像上传表单页面
   """
   if request.method == 'POST':
       # 接受头像字段
       avatar = request.files['avatar']
       # 判断文件是否上传,已经上传文件类型是否正确
       if avatar and allowed_file(avatar.filename):
           # 生成一个随机文件名
           filename = random_file(avatar.filename)
           # 保存文件
           avatar.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
           return redirect(url_for('uploaded_file', filename=filename))

   return render_template('upload.html')


@app.route('/uploads/<filename>')
def uploaded_file(filename):
   """
   显示上传头像
   :param filename: 文件名
   :return: 真实文件路径
   """
   return send_from_directory(app.config['UPLOAD_FOLDER'], filename)


if __name__ == '__main__':
   app.run(debug=True)

执行run.py程序文件,在浏览器中输入网址: http://127.0.0.1:5000/upload,显示上传图片页面,单击【浏览】按钮,弹出一个选择框,选择一个图片后,单击【打开】按钮,会将图片文件名显示在【浏览】按钮右侧。

单击【提交】按钮上传文件,如果上传成功,页面将跳转至uploads,在该页面显示图片内容,就可以显示出该图片。

 

 

 

全部评论