Python Flask:使用扩展实现
目录
Flask-Uploads简介
Flask-Uploads帮你简化了大部分操作。比如在上篇文章中,我们需要自己设置一个集合来设置允许哪些类型的文件(ALLOWED_EXTENSIONS),而Flask-Uploads已经把常用的文件类型分好类,你只需要导入相应的集合名称,比如IMAGES、TEXT、AUDIO等等(默认配置为DEFAULTS,包括TEXT + DOCUMENTS + IMAGES + DATA)。除此之外,你还可以配置全部允许(All)、除某些文件类型外全允许(AllExcept())。这些集合也可以组合使用(比如IMAGES+TEXT)。
Flask-Uploads操作
上传配置
因为Flask-Uploads允许你创建不同的set(代表你上传的文件的集合),所以配置时要把下面的FILES替换成你的set名。
比如文件储存地址设置:
UPLOADED_FILES_DEST = '/path/to/the/uploads'
如果你的set叫photos,那么这条设置就改成:
UPLOADED_PHOTOS_DEST = '/path/to/the/uploads'
你也可以设置一个默认的配置:
UPLOADS_DEFAULT_DEST = '/path/to/the/uploads'
更多的可用配置见文档。
安全问题
文件类型过滤
创建一个set(通过实例化UploadSet()类实现),然后使用configure_uploads()方法注册并完成相应的配置(类似大多数扩展提供的初始化类),传入当前应用实例和set:
photos = UploadSet('photos', IMAGES) configure_uploads(app, photos)
这里的photos是set的名字,它很重要。因为接下来它就代表你已经保存的文件,对它调用save()方法保存文件,对它调用url()获取文件url,对它调用path()获取文件的绝对地址……(你可以把它类比成代表数据库的db)
文件名过滤
不再需要secure_filename()函数来处理文件名,使用set的save()方法直接保存从request对象获取的文件,将返回处理后的文件名:
filename = photos.save(request.files['photo'])
可能还需要再提醒一下,这里的['photo']是input字段的name值。
限制文件大小
导入patch_request_class()函数,传入应用实例和大小(默认为16MB),比如:
patch_request_class(app)
或是
patch_request_class(app, 32 * 1024 * 1024) # 或是从配置里读取大小
获取文件
你不必再创建新的视图函数来获取文件,Flask-Uploads自带了一个视图函数,当你对一个set(比如我们上面创建的photos)使用url()方法(传入文件名作为参数),比如:
photos.url('demo.jpg')
它会返回一个文件的url:
http://example.com/_uploads/photos/demo.jpg # /<setname>/<path:filename>
完整实现
同样是一个图片上传的demo,这次要简单的多。
# -*- coding: utf-8 -*- import os from flask import Flask, request from flask_uploads import UploadSet, configure_uploads, IMAGES,\ patch_request_class app = Flask(__name__) app.config['UPLOADED_PHOTOS_DEST'] = os.getcwd() # 文件储存地址 photos = UploadSet('photos', IMAGES) configure_uploads(app, photos) patch_request_class(app) # 文件大小限制,默认为16MB html = ''' <!DOCTYPE html> <title>Upload File</title> <h1>图片上传</h1> <form method=post enctype=multipart/form-data> <input type=file name=photo> <input type=submit value=上传> </form> ''' @app.route('/', methods=['GET', 'POST']) def upload_file(): if request.method == 'POST' and 'photo' in request.files: filename = photos.save(request.files['photo']) file_url = photos.url(filename) return html + '<br><img src=' + file_url + '>' return html if __name__ == '__main__': app.run()
注:视图函数里的两个‘photo’均指的是input字段的name值。
Gist地址:https://gist.github.com/greyli/addff01c19ddca78cddf386800e57045
大型项目配置
有同学问到这个,补充一下。在大型项目里,可以像其他扩展一样,在程序工厂函数里初始化,在表单文件里导入set。
__init__.py:
# -*-coding: utf-8-*- from flask import Flask from flask_bootstrap import Bootstrap from flask_mail import Mail from flask_moment import Moment from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager from config import config from flask_uploads import UploadSet, configure_uploads, IMAGES # 导入 bootstrap = Bootstrap() mail = Mail() moment = Moment() db = SQLAlchemy() photos = UploadSet('photos', IMAGES) # 创建set def create_app(config_name): app = Flask(__name__) app.config.from_object(config[config_name]) config[config_name].init_app(app) bootstrap.init_app(app) mail.init_app(app) moment.init_app(app) db.init_app(app) configure_uploads(app, photos) # 初始化 return app
在forms.py或views.py中导入set:
from .. import photos
怎么导入视你的目录结构而定,这里的目录结构如下,photos放在__init__.py文件里:
app/ - __init__.py - main/ - forms.py - ...
相关链接
- Flask-Uploads文档:http://pythonhosted.org/Flask-Uploads/
- Flask-Uploads项目地址:https://github.com/maxcountryman/flask-uploads
- - - - -
更多关于Flask和Web开发的原创内容,欢迎关注知乎专栏 - Hello, Flask!。