文件上传与邮件发送
原生上传
-
模板文件
<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__) 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
等实现文件上传 - 使用:
- 各种配置及对象创建
- 注意对象创建的先后顺序
- 上传文件的校验处理过程与上面一样
- 说明:代码见项目《03-full-upload》
flask-mail
说明:专门用来实现邮件发送的扩展库,使用非常方便。
安装:
pip install flask-mail
-
使用:
from flask_mail import Mail, Message import os # 邮件配置,一定要放在对象创建之前 # 邮箱服务器 app.config['MAIL_SERVER'] = 'smtp.1000phone.com' # 用户名 app.config['MAIL_USERNAME'] = 'lijie@1000phone.com' # 密码 app.config['MAIL_PASSWORD'] = os.getenv('MAIL_PASSWORD', '123456') # 创建发送邮件的对象 mail = Mail(app) @app.route('/send/') def send(): # 创建邮件消息对象 msg = Message('账户激活', recipients=['1819974273@qq.com'], 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('账户激活', '1819974273@qq.com', '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_USR_SSL'] = True