使用Flask-Dropzone在Flask程序中實現文件上傳

某天在Stack Overflow上看到一個 關於Dropzone.js的問題,研究以後寫了一個回答。我發現,若是有一個集成Dropzone.js到Flask,而且簡化設置步驟的擴展,確定要比其餘上傳方式簡單的多——因而就有了 Flask-Dropzone


Dropzone.js是一個提供文件上傳、驗證、預覽、上傳進度條等功能的JavaScript庫。Flask-Dropzone在模板中提供了一些方法來幫助你建立上傳區域,引入相關資源。你只須要添加一些配置就能夠實現上傳類型的過濾,文件大小限制,上傳後跳轉等功能。固然,你還要本身編寫視圖函數來處理和保存文件,並進行服務器端的二次驗證。若是你不熟悉服務器端的上傳文件處理,能夠考慮瀏覽一下這篇 《Flask文件上傳(一):原生實現》
《Flask Web開發實戰》中的第3個示例程序( 圖片社交程序Albumy)使用了這個擴展。

用法介紹

安裝

$ pip install flask-dropzone複製代碼

初始化

和其餘擴展相似,你能夠經過實例化Dropzone類,並傳入程序實例app進行初始化:
from flask_dropzone import Dropzone

app = Flask(__name__)
dropzone = Dropzone(app)複製代碼
在使用工廠函數建立程序實例時,你也可使用init_app()方法:
from flask_dropzone import Dropzone

dropzone = Dropzone()

def create_app():
    app = Flask(__name__)
    dropzone.init_app(app)
    return app複製代碼

引入Dropzone.js資源

你須要本身手動編寫引入Dropzone.js的CSS和JavaScript資源的語句。在開發時,或對於玩具項目,你能夠可使用Flask-Dropzone提供的兩個快捷方法:
<head> ... {{ dropzone.load_css() }} </head> <body> ... {{ dropzone.load_js() }} </body>複製代碼

建立並美化上傳區域

若是你不須要對上傳區域的樣式有太多控制,那麼你只須要在想要渲染上傳區域的地方使用dropzone.create()方法:
{{ dropzone.create(action='處理上傳文件的路由URL') }}複製代碼
記得把action參數的值更改爲你要處理文件上傳的的URL。你可使用dropzone.style()方法爲上傳區域添加簡單的自定義樣式:
<head>
...  <!-- 在引入Dropzone.js的CSS文件後調用style()方法 -->
{{ dropzone.style('border: 2px dashed #0087F7; margin: 10%') }}
</head>複製代碼
上傳區域的截圖示例以下所示:

在服務器端處理並保存上傳文件

當文件被拖拽到上傳區域,或是點擊上傳區域選擇上傳文件後,這些文件會以AJAX請求的形式發送到你在dropzone.create()方法中使用action參數傳入的URL。咱們須要在服務器端建立對應的視圖函數來處理這些請求,下面是一個最基本的示例:
import os

from flask import Flask, request
from flask_dropzone import Dropzone

app = Flask(__name__)

dropzone = Dropzone(app)

@app.route('/uploads', methods=['GET', 'POST'])
def upload():

    if request.method == 'POST':  # 若是請求類型爲POST,說明是文件上傳請求
        f = request.files.get('file')  # 獲取文件對象
        f.save(os.path.join('the/path/to/save', f.filename))  # 保存文件

    return 'upload template'  # 渲染上傳頁面複製代碼

上傳完成後重定向

這裏須要注意的是,由於Dropzone.js經過AJAX請求提交文件,因此你無法在保存文件後將頁面重定向。對於這個問題,你可使用配置變量DROPZONE_REDIRECT_VIEW設置上傳完成後跳轉到的目標端點,或是添加一個按鈕讓用戶本身點擊進行跳轉。

服務器端驗證

儘管Dropzone.js能夠在前端對用戶提交的文件進行驗證,但爲了安全考慮,咱們仍然須要在服務器端進行二次驗證。在服務器端驗證時,若是驗證出錯,咱們不能像往常那樣使用flash()函數「閃現」錯誤消息,由於AJAX請求接受到響應後並不會重載頁面,因此不會顯示經過flash()函數發送的消息。正確的作法是返回400錯誤響應,使用錯誤消息做爲響應的主體。下面是一個簡單的進行服務器端驗證並返回錯誤消息得示例:
@app.route('/', methods=['POST', 'GET'])
def upload():
    if request.method == 'POST':
        f = request.files.get('file')
        if f.filename.split('.')[1] != 'png':
            return 'PNG only!', 400  # return the error message, with a proper 4XX code
        f.save(os.path.join('the/path/to/save', f.filename))
    return render_template('index.html')複製代碼
在上面的代碼中,咱們驗證圖片是否是png格式,若是不是就返回一個錯誤提示,在服務器端會在圖片下面看到咱們返回的錯誤消息:

完整的配置列表

Flask-Dropzone提供了豐富的配置變量,你可使用它們對Dropzone.js進行各種配置。很遺憾掘金的編輯器不支持表格,因此這裏只能插入一張圖片,若是你須要文本,能夠訪問 這篇文章

這些配置的用法你能夠參考Flask-Drozone的 文檔或是 示例程序瞭解,這裏咱們僅簡單介紹一下對文件類型進行過濾的設置方法。

設置文件類型過濾

Flask-Dropzone內置了一些文件類型(經過MIME定義),可選的值和對應的文件類型以下所示:
  • default:默認值,運行全部類型
  • image:圖片
  • audio:音頻
  • video:視頻
  • text:文本
  • app:程序
你須要爲DROPZONE_ALLOWED_FILE_TYPE設置對應的值,好比下面設置僅容許上傳圖片:
app.config['DROPZONE_ALLOWED_FILE_TYPE'] = 'image'複製代碼
若是你想要本身定義容許的文件類型列表,那麼你須要將DROPZONE_ALLOWED_FILE_CUSTOM設置True,而後傳入一個包含容許的文件後綴名列表組成的字符串給DROPZONE_ALLOWED_FILE_TYPE變量,使用逗號分隔多個後綴名,好比:
app.config['DROPZONE_ALLOWED_FILE_CUSTOM'] = True
app.config['DROPZONE_ALLOWED_FILE_TYPE'] = 'image/*, .pdf, .txt'複製代碼
對於平行上傳、CSRF保護等內容的具體實現方法你能夠參考 文檔瞭解。不過,這個項目目前尚未建立完善的文檔,暫時只是寫到README裏,若是你發現了英文語法或拼寫錯誤,歡迎指正,同時也歡迎爲項目貢獻代碼。

示例程序

Flask-Dropzone的Git倉庫中的 examples目錄下包含4個示例程序,分別演示了基本用法、CSRF保護、平行上傳和上傳完成後跳轉四個功能。
另外, helloflask倉庫裏在demos/form目錄下的示例程序也包含一個Flask-Dropzone使用示例。

相關連接

相關文章
相關標籤/搜索