章节索引 :

Flask 实现文件上传及文件访问

文件上传功能在很多网站上面都有,比如智联、拉钩、Boss 等各大招聘网站,你可以在这些网站上面上传你的简历文件并快速的发送给各个公司的 HR,可以说是非常方便了。那么这节课我们就来使用 Flask 框架实现一个文件上传的功能,并且上传之后能正常访问到这个文件。

1. 程序功能和结构

1.1 程序功能

用户通过浏览器进行上传文件和下载文件,界面如下所示:

图片描述

用户选择文件,点击上传文件按钮后,开始上传文件。上传文件成功过后,上传的文件会出现在下载文件清单中,点击文件名即可下载文件。

1.2 程序结构

例子包括 5 个源文件,如下表所示:

程序 说明
app.py Flask 后端程序,实现文件上传
templates/index.html 上传和下载文件的页面模板
templates/upload.html 上传成功后的页面模板
upload/ 用于存放已经上传的文件的目录
upload/a.txt 已经上传的文件,用于测试
upload/b.txt 已经上传的文件,用于测试

1.3 源程序下载

2. 后端程序 app.py

2.1 引入相关库

#!/usr/bin/python3
from flask import Flask, render_template, request, send_from_directory
import os

app = Flask(__name__)

从 flask 模块中引入 request 对象,request 对象中的属性 files 记录了上传文件的相关信息;从 flask 模块中引入函数 send_from_directory,该函数用于实现下载文件。

2.2 设置 / 路由

@app.route('/')
def index():
    entries = os.listdir('./upload')
    return render_template('index.html', entries = entries)

设置访问路径 / 时,使用函数 index 进行处理,函数 index 列出目录 upload 下所有的文件名,作为参数传给首页的模板 index.html。在首页 index.html 中根据 entries 显示每个文件的下载链接。

2.3 设置 /upload 路由

@app.route('/upload', methods=['POST'])
def upload():
    f = request.files['file']
    path = os.path.join('./upload', f.filename)
    f.save(path)
    return render_template('upload.html')

设置访问路径 /upload 时,使用函数 upload 进行处理。函数 upload 从 request 对象中获取上传的文件信息,request.files 是一个字典,使用表单中的文件字段名作为索引。

在第 5 行,方法 f.save 将文件保存到指定路径 path 中。如果上传的文件名是 test.txt,则 path 为 ./upload/test.txt。

在第 6 行,在服务端保存上传文件后,渲染页面模板 upload.html,通知用户已经上传成功。

2.4 设置 /files 路由

@app.route('/files/<filename>')
def files(filename):
    return send_from_directory('./upload', filename, as_attachment=True)

app.run(debug = True)

每个文件都有一个下载链接,形式为 /files/ 文件名,假如文件名为 test.txt,则下载链接为 /files/test.txt。

设置访问路径 /files/<filename> 时,使用函数 files 进行处理,其中 <filename> 表示访问路径 URL 中文件的名称,它作为参数传递给函数 files。函数 files 调用 send_from_directory 将 upload 目录下的文件发送给客户,as_attachment=True 表示文件作为附件下载。

3. 页面模板 upload.html

<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>

<body>
<h1>上传成功</h1>
<a href='/'>返回主页</a>
</body>
</html>

在服务端保存上传文件后,服务端返回页面模板 upload.html,通知已经上传成功。用户点击 "返回主页",可以返回到网站根页面,在根页面可以查看到所有已经上传的文件,并下载。

4. 页面模板 index.html

访问路径 / 时,显示 index.html,包括两部分内容:

  • 上传文件表单
  • 下载文件清单

4.1 上传文件

<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>

<body>
<h2>上传文件</h2>
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file" class="input">
    <input type="submit" value="上传" class="input button">
</form>

定义上传文件表单 form,使用 POST 方法提交给服务端 /upload 页面处理,属性 enctype=“multipart/form-data” 表示表单中包含有上传文件的数据需要处理。

4.2 下载文件

<h2>下载文件</h2>
<ol>
{% for entry in entries %}
    <li><a href='/files/{{entry}}'>{{entry}}</a>
{% endfor %}
</ol>
</body>
</html>

在 2.2 小节,访问路径 / 时,处理函数 index 列出目录 upload 下所有的文件名,作为参数传给首页的模板 index.html。假设当前 upload 目录下存在 3 个文件: a.txt、b.txt、c.txt,则 entries 为 [‘a.txt’, ‘b.txt’, ‘c.txt’],页面模板被渲染为:

<h2>下载文件</h2>
<ol>
    <li><a href='/files/a.txt'>a.txt</a>
    <li><a href='/files/b.txt'>b.txt</a>
    <li><a href='/files/c.txt'>c.txt</a>        
</ol>

用户点击文件名链接后,即可下载相应的文件。

5. 小结

本小节讲解了如何上传和下载文件,使用思维导图概括如下:

图片描述