Flask:04-五分鐘輕鬆理解學會:檔案上傳與郵件傳送(自帶優化)
檔案上傳與郵件傳送
-
可以按照標題分別直接貼上對應的資料夾,執行直接用:
原生上傳
-
模板檔案
<form method="post" enctype="multipart/form-data"> <input type="file" name="photo" /><br /> <input type="submit" value="上傳" /> </form>
-
檢視函式
@app.route('/upload/', methods=['GET', 'POST']) def upload(): if request.method == 'POST': # 獲取上傳物件 photo = request.files.get('photo') if photo: # 儲存上傳檔案,引數是檔案儲存的路徑名 photo.save(photo.filename) return '檔案上傳成功' return '檔案上傳失敗' return render_template('upload.html')
-
優化完善
import os from flask import send_from_directory # 上傳檔案儲存位置 app.config['UPLOADED_FOLDER'] = os.path.join(os.getcwd(), 'static/upload') # 請求大小(檔案大小限制) app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024 * 8 # 判斷是否是允許的檔案型別 def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_SUFFIX # 展示上傳的檔案 @app.route('/uploaded/<filename>') def upladed(filename): # 安全的傳送檔案 return send_from_directory(app.config['UPLOADED_FOLDER'], filename) @app.route('/upload/', methods=['GET', 'POST']) def upload(): img_url = None if request.method == 'POST': # 獲取上傳物件 photo = request.files.get('photo') # 儲存前驗證檔案的型別 if photo and allowed_file(photo.filename): # 拼接檔案儲存的完整路徑名 pathname = os.path.join(app.config['UPLOADED_FOLDER'], photo.filename) # 儲存上傳檔案,引數是檔案儲存的路徑名 photo.save(pathname) img_url = url_for('upladed', filename=photo.filename) return render_template('upload.html', img_url=img_url)
優化:大小限定、型別限定、儲存位置、檢視上傳檔案
flask-uploads
-
說明:極大地優化了檔案上傳的操作,使用非常方便
-
安裝:
pip install flask-uploads
-
使用:
- 配置
from flask_uploads import UploadSet, IMAGES from flask_uploads import configure_uploads from flask_uploads import patch_request_class import os app = Flask(__name__) # 設定檔案的大小:8M=8*1024*1024k app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024 * 8 app.config['UPLOADED_PHOTOS_DEST'] = os.path.join(os.getcwd(), 'static/upload') # 建立上傳物件,指定名字和上傳檔案的型別 photos = UploadSet('photos', IMAGES) # 配置上傳物件 configure_uploads(app, photos) # 設定上傳檔案大小,預設64M,設定為None,大小由MAX_CONTENT_LENGTH決定 patch_request_class(app, size=None)
- 檢視函式
@app.route('/upload/', methods=['GET', 'POST']) def upload(): img_url = None if request.method == 'POST': # 獲取上傳物件 photo = request.files.get('photo') if photo: # 儲存上傳檔案 photos.save(photo) # 獲取上傳檔案的地址 img_url = photos.url(photo.filename) return render_template('upload.html', img_url=img_url)
- 優化上傳:生成隨機檔名,生成縮圖(PIL模組,只支援py2,py3中使用需要安裝pillow)
# 生成隨機字串 def random_string(length=32): import random base_str = 'abcdefghijklmnopqrstuvwxyz1234567890' return ''.join(random.choice(base_str) for i in range(length)) @app.route('/upload/', methods=['GET', 'POST']) def upload(): img_url = None if request.method == 'POST': # 獲取上傳物件 photo = request.files.get('photo') if photo: # 提取檔案字尾 suffix = os.path.splitext(photo.filename)[1] # 生成隨機檔名 filename = random_string() + suffix # 儲存上傳檔案 photos.save(photo, name=filename) # 生成縮圖 from PIL import Image # 拼接完整路徑名 pathname = os.path.join(app.config['UPLOADED_PHOTOS_DEST'], filename) # 開啟檔案 img = Image.open(pathname) # 設定大小 img.thumbnail((64, 64)) # 儲存修改後的圖片 img.save(pathname) # 獲取上傳檔案的地址 img_url = photos.url(filename) return render_template('upload.html', img_url=img_url)
綜合使用
-
要求:結合
flask-bootstrap、flask-wtf、flask-uploads
等實現檔案上傳 -
使用:
- 各種配置及物件建立
- 注意物件建立的先後順序
- 上傳檔案的校驗處理過程與上面一樣
flask-mail
-
說明:專門用來實現郵件傳送的擴充套件庫,使用非常方便。
-
安裝:
pip install flask-mail
-
使用:
from flask_mail import Mail, Message import os # 郵件配置,一定要放在物件建立之前 # 郵箱伺服器:不同型別郵箱伺服器不同,不知道的請百度 app.config['MAIL_SERVER'] = 'smtp.xxx.com' # 使用者名稱 app.config['MAIL_USERNAME'] = '[email protected]' # 密碼:如果密碼新增到了環境變數可以直接引用'MAIL_PASSWORD',否則直接把'123456'換成自己的郵箱密碼。 app.config['MAIL_PASSWORD'] = os.getenv('MAIL_PASSWORD', '123456') # 建立傳送郵件的物件 mail = Mail(app) @app.route('/send/') def send(): # 建立郵件訊息物件 msg = Message('賬戶啟用', recipients=['[email protected]'], sender=app.config['MAIL_USERNAME']) # 設定郵件內容 msg.html = '恭喜你,中獎了!' # 傳送郵件 mail.send(msg) return '郵件傳送成功'
-
總結:
- 書寫郵箱相關配置
- 建立傳送郵件的(Mail)物件
- 建立郵件訊息(Message)物件
- 使用mail的send方法傳送郵件
-
封裝函式傳送郵件
# 封裝函式傳送郵件 def send_mail(subject, to, template, **kwargs): # 處理郵件接收者 if isinstance(to, list): recipients = to elif isinstance(to, str): recipients = to.split(',') else: raise Exception('郵件接收者引數有誤') # 建立郵件訊息物件 msg = Message(subject=subject, recipients=recipients, sender=app.config['MAIL_USERNAME']) # 設定郵件內容 msg.html = render_template(template, **kwargs) # 傳送郵件 mail.send(msg) @app.route('/send/') def send(): # 呼叫函式即可傳送郵件 send_mail('賬戶啟用', '[email protected]', 'activate.html', name='八戒') return '郵件傳送成功'
-
非同步傳送郵件
from flask import current_app from threading import Thread # 非同步傳送郵件 def async_send_mail(app, msg): # 郵件傳送必須在程式上下文中進行 # 新的執行緒沒有上下文,因此需要手動建立上下文 with app.app_context(): mail.send(msg) # 封裝函式傳送郵件 def send_mail(subject, to, template, **kwargs): # 處理郵件接收者 if isinstance(to, list): recipients = to elif isinstance(to, str): recipients = to.split(',') else: raise Exception('郵件接收者引數有誤') # 從代理中獲取原始物件 app = current_app._get_current_object() # 建立郵件訊息物件 msg = Message(subject=subject,recipients=recipients,sender=app.config['MAIL_USERNAME']) # 設定郵件內容 msg.html = render_template(template, **kwargs) # 傳送郵件:同步傳送,會阻塞執行 # mail.send(msg) # 建立一個執行緒,在新的執行緒中傳送郵件 thr = Thread(target=async_send_mail, args=(app, msg)) # 啟動執行緒 thr.start() # 返回執行緒 return thr
-
QQ郵箱傳送配置
# 密碼,QQ郵箱需要使用授權碼 app.config['MAIL_PASSWORD'] = os.getenv('MAIL_PASSWORD', '123456') # QQ郵箱配置 # app.config['MAIL_PORT'] = 465 # 加密傳輸 # app.config['MAIL_USE_SSL'] = True