# Flask實作_ext_15_Flask_Uploads搭配Flask-wtf
###### tags: `flask` `flask_ext` `python` `uploads` `wtform`
:::danger
前置閱讀:
* [Flask實作_ext_14_Flask_Uploads](https://hackmd.io/s/BJPLnPHJX)
:::
在[Flask實作_ext_14_Flask_Uploads](https://hackmd.io/s/BJPLnPHJX)中提到,`flask-uploads`可以搭配`flask-wtf`一起使用,讓我們一起來看怎麼結合應用。
## 範例
承接[Flask實作_ext_14_Flask_Uploads](https://hackmd.io/s/BJPLnPHJX)範例,我們已經有完成一個簡單的檔案上傳的板,但實作上我們會使用`flask-wtf`來快速開發表單,這時候可以利用`flask-wtf`的`FileField`、`FileRequired`、`FileAllowed`來搭配`flask-uploads`作業,這是`flask-wtf`早就已經預留好的接口。
我們加追import`flask-wtf`與`wtform`的部份package,如下:
```python=
from flask_wtf import FlaskForm
from wtforms import SubmitField
from flask_wtf.file import FileField, FileAllowed, FileRequired
```
然後設置一個很簡單的Form,如下:
```python=
class FormUploads(FlaskForm):
btn_uploads = FileField('uploads', validators=[
FileAllowed(abc, 'IMAGE ONLY'),
FileRequired('IMAGE REQUIRED PLEASE')
])
submit = SubmitField('Upload_IMG')
```
第2行:設置一個`FileField`,加入兩個驗證項,一個是必需有照片,一個是只允許照片。
第3行:`FileAllowed`的第一個參數是`UploadSet`的物件名稱,我們案例為`abc`。
新增一個View Function<sub>(在同一個Python文件上)</sub>,如下:
```python=
@app.route('/upload_wtf/', methods=['GET','POST'])
def upload_wtf():
form = FormUploads()
if form.validate_on_submit():
file_name = abc.save(form.btn_uploads.data)
file_url = abc.url(file_name)
print(file_name, file_url)
return render_template('abc.html', form=form, file_url=file_url)
else:
file_url=None
return render_template('abc.html', form=form, file_url = file_url)
```
第5行:利用`UploadSet.save`來取得`form`的資料,不再是利用`request`來取得資料
第6行:利用`UploadSet.url`來取得路徑
第10行:設置`file_url`這參數的用意是為了在上傳之後把照片顯示在畫面上,所以初始設置為`None`
最後再加入一個Html來渲染頁面,如下:
```htmlmixed=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="POST" action="{{ url_for('upload_wtf') }}" enctype="multipart/form-data">
<div>
{{ form.hidden_tag() }}
{{ form.btn_uploads}}
{# error message #}
{% for error in form.btn_uploads.errors %}
<span>{{ error }}</span>
{% endfor %}
{{ form.submit }}
</div>
<div>
{% if file_url %}
<img src="{{ file_url }}" alt="">
{% endif %}
</div>
</form>
</body>
</html>
```
第8行:記得設置`enctype="multipart/form-data"`
第13行:錯誤訊息設置
第19行:判斷`file_url`是否有東西,有的話就顯示照片
接下來我們一起來測試一下專案連結`http://127.0.0.1:5000/upload_wtf/`,如下:
* 首先測試的是沒有選擇檔案的情況下按下上傳照片

* 測試檔案上傳錯誤格式

* 測試上傳正常的照片


如果有多檔上傳需求的話,則是在Html上設置欄位的時候給予屬性`{{ form.btn_uploads(multiple="multiple") }}`就可以滿足多選功能,下圖是設置與否的Html差異,當然如果設置了多選的話我們的後端這邊也必需調整為迴圈來取值。

## 結論
透過上面的案例我們看到結合`flask_wtf.ext`的三個類別可以讓專案快速的整合`flask-uploads`來完成簡單的檔案上傳應用,進階如拖拉上傳就可以利用HTML5或是JQUERY來達成,這部份就不多說。
最後,要注意到官方文件有提到,如果`flask_wtf`的`FileFelid`沒有搭配`flask-uploads`一起使用的話,必需使用`from werkzeug.utils import secure_filename`的`serure_filename`來避免資訊安全問題,務必特別注意。
**Flask_Uploads:**[Flask實作_ext_14_Flask_Uploads](https://hackmd.io/s/BJPLnPHJX)