Hello, Flask!
首发于Hello, Flask!
Flask文件上传(三):完整实现

Flask文件上传(三):完整实现

上篇文章里,我们使用扩展简化了文件上传的步骤。这次使用Flask-WTF来增强表单功能:处理表单验证,显示错误信息。因为同时使用Flask-Uploads,上传部分的实现见前两篇文章。



Flask文件上传系列目录

  1. Flask文件上传(一):原生实现
  2. Flask文件上传(二):使用扩展实现
  3. Flask文件上传(三):完整实现
  4. Flask文件上传(四):文件管理与多文件上传
  5. Flask文件上传(五):拖拽上传和进度条


使用Flask-WTF

如果你对Flask-WTF还不熟悉,可以看看之前的几篇文章,或是读读文档。

1、初始化

为CSRF保护创建SECRET_KEY设置:

app.config['SECRET_KEY'] = 'a random string'

2、创建表单

使用Flask-WTF提供的FileField字段以及FileRequiredFileAllowed验证函数

from flask_wtf.file import FileField, FileRequired, FileAllowed

可以传入错误信息:

photo = FileField(u'图片上传', validators=[
    FileAllowed(photos, u'只能上传图片!'), 
    FileRequired(u'文件未选择!')
])
这里FileAllowed()的第一个参数是使用Flask-Uploads设置的set名称,如果不使用Flask-Uploads,可以替换成文件后缀组成的列表,比如['jpg', 'png']。

3、在模板中渲染错误信息

{% for error in form.field.errors %}
    {{ error }}
{% endfor %}

这里面的field是字段名称,比如上面的photo。

4、获取文件

文件数据不再从request对象获取,而是使用data方法获取:

filename = photos.save(form.photo.data)

完整实现

这次把HTML代码放在了单独的文件,效果仍然和之前两个版本相同。

upload.py

# -*- coding: utf-8 -*-
import os

from flask import Flask, render_template
from flask_uploads import UploadSet, configure_uploads, IMAGES, patch_request_class
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired, FileAllowed
from wtforms import SubmitField

app = Flask(__name__)
app.config['SECRET_KEY'] = 'I have a dream'
app.config['UPLOADED_PHOTOS_DEST'] = os.getcwd()

photos = UploadSet('photos', IMAGES)
configure_uploads(app, photos)
patch_request_class(app)  # set maximum file size, default is 16MB


class UploadForm(FlaskForm):
    photo = FileField(validators=[
        FileAllowed(photos, u'只能上传图片!'), 
        FileRequired(u'文件未选择!')])
    submit = SubmitField(u'上传')


@app.route('/', methods=['GET', 'POST'])
def upload_file():
    form = UploadForm()
    if form.validate_on_submit():
        filename = photos.save(form.photo.data)
        file_url = photos.url(filename)
    else:
        file_url = None
    return render_template('index.html', form=form, file_url=file_url)


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

模板文件:index.html

<!DOCTYPE html>
<title>Upload File</title>
<h1>图片上传</h1>
<form method="POST" enctype="multipart/form-data">
     {{ form.hidden_tag() }}
     {{ form.photo }}
     {% for error in form.photo.errors %}
         <span style="color: red;">{{ error }}</span>
     {% endfor %}
     {{ form.submit }}
</form>

{% if file_url %}
<br><img src="{{ file_url }}">
{% endif %}

Gist地址:gist.github.com/greyli/



文件在数据库的表示

肯定有人想把文件存到数据库里,胡乱试了一通后发现没法子。甚至还有人想要把文件转换成base64编码存起来。这不是一心想把数据库玩坏么……数据库不是用来存文件的,文件应该放到硬盘里。数据库里只存储文件名。

存储文件名,然后使用的时候在视图函数里通过Flask-Uploads提供的url()方法获取URL,或是用Flask提供的send_from_directory()方法获取(参考这个系列第一篇文章)。

更正:出于文件管理的需要,不应该直接存储URL。



相关链接


- - - - -

更多关于Flask和Web开发的原创内容,欢迎关注知乎专栏 - Hello, Flask!

文章被以下专栏收录

    大家好,我是李辉,一个Python程序员。在这个专栏,你会看到我学习和使用Flask的经验和总结,你还会看到我所有的发明创造,以及它们的实现方法。欢迎加入这场Flask之旅,拿好你的小键盘,上车吧!helloflask.com