Editor.MD的Flask圖片上傳實戰(zhàn)
繼上篇 基于Flask的Markdown編輯器實踐選擇的Editor.MD為博客提供的MarkDown編輯器自帶圖片上傳接口走孽,如果不使用Flask-Uploads的話也是很簡便的。這篇相當(dāng)于上篇的一個補充和拓展棵譬。
在html里添加這三行:imageUploadURL
里填后面用的上傳路由
<script type="text/javascript">
$(function () {
editormd("fancy-editormd", {
// ...
imageUpload : true,
imageFormats : [ "jpg", "jpeg", "gif", "png", "bmp", "webp" ],
imageUploadURL : "{{ url_for('.upload') }}",
});
});
</script>
-
同域上傳
如果要同域上傳射窒,可以這樣寫,在path字段改為相應(yīng)的圖片上傳目錄即可:
@admin_bp.route('/upload/',methods=['POST'])
@login_required
def upload():
file=request.files.get('editormd-image-file')
if not file:
res={
'success':0,
'message':'上傳失敗'
}
else:
ex=os.path.splitext(file.filename)[1]
filename=datetime.now().strftime('%Y%m%d%H%M%S')+ex
file.save(filename)
res={
'success':1,
'message':'上傳成功',
'url':url_for('.image',name=filename)
}
return jsonify(res)
@admin_bp.route('/image/<name>')
@csrf.exempt
def image(name):
with open(os.path.join('../uploads',name),'rb') as f:
resp=Response(f.read(),mimetype="image/jpeg")
return resp
-
跨域上傳
如果跨域上傳,國內(nèi)圖床可以選則常用的七牛云或者阿里云,都大同小異缕贡。
這里我以七牛云為例, 七牛云有提供Python-SDK拣播,還是很便利的晾咪,另外Github有Flask-QiniuStorage——七牛云存儲Flask擴展,Qiniu Storage for Flask
使用教程簡單明了贮配,首先pip安裝:(利用pipenv)
pipenv install Flask-QiniuStorage
工廠函數(shù)中將其實例化:
from flask_qiniustorage import Qiniu
# ...
qiniu_store = Qiniu()
# ...
from cryptic.extensions import qiniu_store
# ...
def register_extensions(app):
qiniu_store.init_app(app)
# ...
類組織配置谍倦,Access key 和 Secret key比較敏感,我們選擇從環(huán)境變量中讀取泪勒,對應(yīng)設(shè)置即可:
QINIU_ACCESS_KEY = os.getenv('ACCESS_KEY')
QINIU_SECRET_KEY = os.getenv('QINIU_KEY')
QQINIU_BUCKET_NAME = '七胖缰空間名稱'
QINIU_BUCKET_DOMAIN = '七牛空間對應(yīng)域名'
這邊七牛云的后臺設(shè)置告一段落圆存,我們回頭看下Editor.MD
:
可知文件接收的參數(shù)為editormd-image-file
前端需要回調(diào)一個固定格式叼旋,用于告知前端狀態(tài)信息與導(dǎo)入的URL地址,如果調(diào)用失敗無需返回url沦辙。
res.json({
success : 1,
message : "這里隨便",
url: imageSrc
})
此時我們差不多就可以編輯上傳路由了:
設(shè)置文件接收的參數(shù)夫植,方法為POST
only
admin.py:
import os
from datetime import datetime
from flask import jsonify, request
from flask_login import login_required
from xxxxx.extensions import qiniu_store
# ...
@admin_bp.route('/upload/',methods=['POST'])
@login_required
def upload():
data=request.files['editormd-image-file']
if not data:
res={
'success':0,
'message':'upload failed'
}
else:
ex=os.path.splitext(data.filename)[1]
filename=datetime.now().strftime('%Y%m%d%H%M%S')+ex
qiniu_store.save(file, filename)
res={
'success':1,
'message':'upload success',
'url':qiniu_store.url(filename)
}
return jsonify(res)
我們嘗試使用request獲取文件,遇到了新問題油讯,我們收獲了一個400錯誤
如果前面定義了CSRF錯誤響應(yīng)捕捉详民。此時我們就收到了一個CSRFError
由于Flask-WTF的CSRF保護開啟,然而Editor.md 的上傳表單中并沒有包含csrftoken陌兑。
要么就都添加csrf驗證沈跨,要么就都關(guān)閉
你可以閱覽Flask-WTF的文檔(http://www.pythondoc.com/flask-wtf/csrf.html)
- 我們可以通過修改請求文件
editormd/plugins/image-dialog/image-dialog.js
來添加csrfToken來解決:
image-dialog.js:
if (settings.crossDomainUpload)
{
action += "&callback=" + settings.uploadCallbackURL + "&dialog_id=editormd-image-dialog-" + guid;
}
var csrfToken = $('meta[name="_token"]').attr('content');
var csrfField = "";
if (csrfToken) {
csrfField = "<input type='hidden' name='_token' value='" + csrfToken + "' />";
}
修改響應(yīng)字段,添加csrfField 變量兔综,修改dialogContent為:
var dialogContent = ( (settings.imageUpload) ? "<form action=\"" + action +"\" target=\"" + iframeName + "\" method=\"post\" enctype=\"multipart/form-data\" class=\"" + classPrefix + "form\">" : "<div class=\"" + classPrefix + "form\">" ) +
( (settings.imageUpload) ? "<iframe name=\"" + iframeName + "\" id=\"" + iframeName + "\" guid=\"" + guid + "\"></iframe>" : "" ) +
"<label>" + imageLang.url + "</label>" +
"<input type=\"text\" data-url />" + (function(){
return (settings.imageUpload) ? "<div class=\"" + classPrefix + "file-input\">" +
"<input type=\"file\" name=\"" + classPrefix + "image-file\" accept=\"image/*\" />" +
csrfField +
"<input type=\"submit\" value=\"" + imageLang.uploadButton + "\" />" +
"</div>" : "";
})() +
"<br/>" +
"<label>" + imageLang.alt + "</label>" +
"<input type=\"text\" value=\"" + selection + "\" data-alt />" +
"<br/>" +
"<label>" + imageLang.link + "</label>" +
"<input type=\"text\" value=\"http://\" data-link />" +
"<br/>" + csrfField +
( (settings.imageUpload) ? "</form>" : "</div>");
這里排版有點亂饿凛,只有單獨起行的的兩個csrfField +
,接下來在post表單做相應(yīng)修改即可软驰。
- 不過既然我選擇了惰性加載CsrfProtect涧窒,我暫時可以先直接通過添加
@csrf_exempt
在view里排除。
于是最終上傳代碼如下:
admin.py:
import os, base64
from datetime import datetime
from flask import jsonify, request
from flask_login import login_required
from xxxxx.extensions import csrf, qiniu_store
# ...
@admin_bp.route('/upload/',methods=['POST'])
@login_required
@csrf_exempt
def upload():
data=request.files['editormd-image-file']
if not data:
res={
'success':0,
'message':'圖片失敗請重試'
}
else:
ex=os.path.splitext(data.filename)[1]
filename=datetime.now().strftime('%Y%m%d%H%M%S')+ex
file = data.stream.read()
file = base64.b64encode(file)
# data.save(filename)
qiniu_store.save(file, filename)
res={
'success':1,
'message':'圖片上傳成功',
'url':qiniu_store.url(filename)
}
return jsonify(res)
jsonify自動添加文件頭碌宴,成功回調(diào)的效果如下杀狡。
至此應(yīng)該都沒什么問題了,如果需要顯示emoji或者代碼高亮這些直接在js腳本里添加相應(yīng)字段即可贰镣,添加必要的css和js文件呜象。