Flask常用扩展(Extentions)
官网;http://flask.pocoo.org/extensions/
1、Flask-Script
说明: 一个flask终端运行的解析器
安装:pip install flask-script
使用
# 导入类库 from flask_script import Manager # 创建对象 manager = Manager(app) # 启动实例 if __name__ == '__main__': # app.run(debug=True, threaded=True, port=5050, host='0.0.0.0') #使用manager.py来启动服务 manager.run()
启动
python manage.py runserver python manage.py runserver -d -r --thread
启动参数
-?,--help # 查看启动设置帮助 -h,--host # 指定主机 -p,--port # 指定端口 --thread # 启动多线程 -d # 开启调试模式 -r # 代码修改后自动加载
2、Flask-Bootstrap
安装:pip install flask-bootstrap
使用
from flask_bootstrap import Bootstrap bootstrap = Bootstrap(app) 事后配置app:bootstrap.init_app(app) {% extends 'bootstrap/base.html' %}
主要block
title | title标签
head | head标签
styles | 引入css
metas | 一组meta标签
body | body标签
navbar | 用户自定义导航条
content | 用户自定义内容
scripts | 用户定义的JS
定义项目基础模板
1.从bootcss.com复制一个顺眼的导航条
2.将container-fluid改为container
3.显示反色导航条:navbar-inverse
4.将圆角改为直角:style=“border-radius: 0px;”
5.根据需要定制显示内容
6.修改折叠目标的定位:data-target=".navbar-collapse"
{% extends ‘bootstrap/base.html’ %}
错误页面定制
定义404错误处理函数
@app.errorhandler(404) def page_not_found(e): return render_template('404.html')
404.html
{% extends 'base.html' %} {% block title %}出错了{% endblock %} {% block pagecontent %} 臣妾实在找不到啊@@ {% endblock %}
反向路由
url_for('var', name='xiaoming', pwd='123456')
url_for('var', name='xiaoming', pwd='123456', _external=True)
加载静态资源
加载图片: <img src="{{ url_for('static', filename='cluo.jpg') }}"> 加载CSS: {% block styles %} {{ super() }} <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='common.css') }}" /> {% endblock %} 加载JS: {% block scripts %} {{ super() }} <script type="text/javascript" src="{{ url_for('static', filename='common.js') }}"> </script> {% endblock %}
3Flask-Mail
说明:是一个邮件发送的扩展库,使用非常方便
安装:pip install flask-mail
基本配置
配置邮箱服务器: app.config['MAIL_SERVER'] = os.environ.get('MAIL_SERVER', 'smtp.qq.com') 配置用户名: app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME', 'xxx@qq.com') 配置密码(或授权码): app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD', '123456')
QQ邮箱的额外配置
app.config['MAIL_DEBUG'] = True # 开启debug,便于调试看信息 app.config['MAIL_SUPPRESS_SEND'] = False # 发送邮件,为True则不发送 app.config['MAIL_SERVER'] = 'smtp.qq.com' # 邮箱服务器 app.config['MAIL_PORT'] = 465 # 端口 app.config['MAIL_USE_SSL'] = True # 重要,qq邮箱需要使用SSL app.config['MAIL_USE_TLS'] = False # 不需要使用TLS app.config['MAIL_DEFAULT_SENDER'] = 'xxx61@qq.com' # 填邮箱,默认发送者
定义邮件消息
创建邮件消息 msg = Message(subject=subject, recipients=[to], sender=app.config['MAIL_USERNAME']) 浏览器打开邮件的样式 msg.html = render_template(template, **kwargs) 配置邮件正文 msg.body = render_template(template, **kwargs)
发送邮件
创建邮件对象:mail = Mail(app)
事后配置app:mail.init_app(app)
创建发送线程:thr = Thread(target=async_send_mail, args=[app, msg])
执行发送线程:thr.start()
发送邮件:mail.send(message=msg)
注意此处要独占应用上下文: # 发送邮件需要程序上下文,新的线程没有上下文,需要手动创建 with app.app_context(): # 发送邮件 mail.send(message=msg)
发送附件
with app.open_resource("image.png") as fp: msg.attach("image.png", "image/png", fp.read())
4、Flask-WTF
a.原生表单
模板文件login.html
<form method="post" action="{{ url_for('check') }}"> 用户名:<input name="username" type="text" /> <input type="submit" value="立即登录" /> </form>
视图函数
#渲染 @app.route('/login/') def login(): return render_template('login.html') #校验 @app.route('/check/', methods=['POST']) def check(): return 'Hello %s !' % request.form['username'] #渲染校验合写 @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') else: return 'Hello %s !' % request.form['username']
一个路由处理时,表单的action属性不用书写,默认提交到当前路由。
b. 说明:WTF是一个用于表单处理的扩展库,提供了CSRF、校验等功能,使用非常方便.
c.安装:pip install flask-wtf
d.使用
导入依赖
导入表单基类:from flask_wtf import FlaskForm
导入控件/字段:from wtforms import StringField, SubmitField
导入验证规则:from wtforms.validators import DataRequired
e.配置CSRF秘钥
app.config[‘SECRET_KEY’] = ‘123456’
f.定义表单类
class NameForm(FlaskForm)
name = StringField(‘用户名’, validators=[DataRequired()])
submit = SubmitField(‘提交’)
# 导入表单基类 from flask_wtf import FlaskForm # 导入字段类型 from wtforms import StringField, SubmitField # 导入验证器类 from wtforms.validators import DataRequired # CSRF需要使用 app.config['SECRET_KEY'] = '123456' # 定义表单类 class NameForm(FlaskForm): name = StringField('用户名', validators=[DataRequired()]) submit = SubmitField('提交')
g.视图函数
创建表单对象: form = NameForm()
分配到模板中进行渲染:return render_template(‘form.html’, form=form)
@app.route('/') def index(): # 创建表单对象 form = NameForm() # 分配到模板中进行渲染 return render_template('form.html', form=form)
h.模板渲染表单
原生渲染
<form> {# CSRF的隐藏字段 #} {{ form.hidden_tag() }} {# name字段,可以指定id、class等属性,定制显示效果 #} {{ form.name.label() }} {{ form.name(id='xxx', class='yyy') }} {# submit字段 #} {{ form.submit() }} </form>
bootstrap渲染
{% extends ‘bootstrap/base.html’ %}
{% import ‘bootstrap/wtf.html’ as wtf %}
渲染表单
{% block content %} {{ wtf.quick_form(form) }} {% endblock %}
表单校验
@app.route('/', methods=['GET', 'POST']) def index(): # 创建表单对象 form = NameForm() # 表单校验 if form.validate_on_submit(): name = form.name.data form.name.data = '' # 分配到模板中进行渲染 return render_template('form.html', form=form, name=name)
重定向
@app.route('/', methods=['GET', 'POST']) def index(): # 创建表单对象 form = NameForm() # 表单校验 if form.validate_on_submit(): session['name'] = form.name.data return redirect(url_for('index')) name = session.get('name') # 分配到模板中进行渲染 return render_template('form.html', form=form, name=name)
常见字段类型
StringField | 普通文本字段 SubmitField | 提交按钮 PasswordField | 密码文本字段 HiddenField | 隐藏文本字段 TextAreaField | 多行文本字段 DateField | 文本字段,datetime.date格式 DateTimeField | 文本字段,datetime.datetime格式 IntegerField | 文本字段,值为整数 FloatField | 文本字段,值为小数 BooleanField | 复选框,值为True或False RadioField | 单选框 SelectField | 下拉框 FileField | 文件上传
常见验证器类
DataRequired | 确保字段有值 Email | 邮箱地址 IPAddress | IP地址 Length | 规定字符长度 EqualTo | 验证两个字段的一致性 URL | 有效的URL NumberRange | 输入数值的范围 Regexp | 正则验证
自定义字段验证
# 定义表单类 class NameForm(FlaskForm): name = StringField('用户名', validators=[DataRequired()]) submit = SubmitField('提交') # 自定义字段验证函数,格式是写一个'validate_字段名'的函数 def validate_name(self, field): if len(field.data) < 6: raise ValidationError('用户名长度不能少于6个字符')
5、flash消息
提交flash消息
@app.route('/', methods=['GET', 'POST']) def index(): # 创建表单对象 form = NameForm() # 表单校验 if form.validate_on_submit(): last_name = session.get('name') # 原来有名字,并且与新的不同 if last_name and last_name != form.name.data: # flash消息 flash('大哥,又换签名了') flash('常换签名,才能吸引眼球') session['name'] = form.name.data return redirect(url_for('index')) name = session.get('name') # 分配到模板中进行渲染 return render_template('form.html', form=form, name=name)
显示消息
{# 获取所有的flash消息,然后遍历显示 #} {% for message in get_flashed_messages() %} <div class="alert alert-warning alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Close"> <span aria-hidden="true">×</span> </button> {{message}} </div> {% endfor %}
提示
若好多页面都有弹出消息,可以将flash消息放在基础模板中展示
6、Flask-Moment
说明
专门负责时间本地化显示的扩展库,使用非常方便
安装
pip install flask-moment
使用
向模板传递时间
# 导入类库 from flask_moment import Moment from datetime import datetime, timedelta # 创建对象 moment = Moment(app) @app.route('/moment/') def mom(): current_time = datetime.utcnow() + timedelta(seconds=-3600) return render_template('moment.html', current_time=current_time)
模板中显示
{# 简单的格式化显示 #} <div>时间:{{ moment(current_time).format('LLLL') }}</div> <div>时间:{{ moment(current_time).format('LLL') }}</div> <div>时间:{{ moment(current_time).format('LL') }}</div> <div>时间:{{ moment(current_time).format('L') }}</div> {# 自定义格式化显示 #} <div>自定义显示:{{ moment(current_time).format('YYYY-MM-DD') }}</div> {# 时间差值显示 #} <div>发表于:{{ moment(current_time).fromNow() }}</div> {# 加载jQuery,因为moment.js依赖,使用bootstrap时可以省略 #} {{ moment.include_jquery() }} {# 加载moment.js #} {{ moment.include_moment() }} {# 设置中文显示 #} {{ moment.locale('zh-CN') }}
提示
格式化显示不要记忆,去官网查询即可
momentjs.com
6、Flask-Uploads
a.原生上传文件
b.模板文件
<html> <head> <title>原生文件上传</title> </head> <body> {% if img_url %} <img src="{{ img_url }}"> {% endif %} <form method="post" enctype="multipart/form-data"> <input type="file" name="photo" /> <input type="submit" value="上传" /> </form> </body> </html>
c.视图函数
@app.route('/upload/', methods=['GET', 'POST']) def upload(): img_url = None if request.method == 'POST': file = request.files.get('photo') if file and allowed_file(file.filename): # 获取文件后缀 suffix = os.path.splitext(file.filename)[1] # 生成随机文件名 filename = random_string() + suffix # 保存上传文件 file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) # 构造上传的文件的访问URL img_url = url_for('uploaded', filename=filename) return render_template('upload.html', img_url=img_url)
相关配置
# 允许上传的文件后缀 ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif']) # 配置上传文件保存位置 app.config['UPLOAD_FOLDER'] = os.getcwd() # 上传文件大小 app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024 * 8
支持函数
判断是否是允许的文件后缀
def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
生成随机的字符串
def random_string(length=32): import random base_str = 'abcdefghijklmnopqrstuvwxyz1234567890' return ''.join(random.choice(base_str) for i in range(length))
获取上传文件
@app.route('/uploaded/<filename>') def uploaded(filename): # 安全的发送文件 return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
注意事项,文件上传失败时,应从哪些方面着手
1.表单的提交方法必须是POST
2.表单的enctype属性必须设置为multipart/form-data
3.上传的字段类型必须为file,并且必须有name属性
4.是否超过运行的最大尺寸
5.文件的保存位置是否有空间,是否有权限
生成缩略图
需要安装pillow库
# 导入图片处理的类,默认PIL不支持python3.x,安装pillow后就可以了 from PIL import Image # 生成缩略图 # 1.打开文件 img = Image.open(pathname) # 2.重设尺寸 img.thumbnail((128, 128)) # 3.保存修改 img.save(pathname)
flask-uploads
说明:在文件上传时,提供了很大的方便,如:文件类型的过滤,校验,文件保存,获取url等
安装:pip install flask-uploads
使用
相关配置
# 上传文件的大小 app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024 * 8 # 上传文件的保存位置 app.config['UPLOADED_PHOTOS_DEST'] = os.getcwd() # 创建上传对象,指定过滤的文件后缀 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' and 'photo' in request.files: # 保存文件 filename = photos.save(request.files['photo']) # 获取保存文件的url img_url = photos.url(filename) return render_template('upload.html', img_url=img_url)
模板文件
同原生的文件上传upload.html
d.结合wtf做文件上传
flask-uploads配置同上
flask-wtf配置
# 导入表单基类 from flask_wtf import FlaskForm # 导入文件上传字段及验证器 from flask_wtf.file import FileField, FileRequired, FileAllowed from wtforms import SubmitField # 上传文件表单类 class UploadForm(FlaskForm): photo = FileField('头像上传', validators=[FileRequired('文件未选择'), FileAllowed(photosUS, message='只能上传图片文件')]) submit = SubmitField('上传')
视图函数
@app.route('/upload/', methods=['GET', 'POST']) def upload(): img_url = None form = UploadForm() if form.validate_on_submit(): # 获取文件后缀 suffix = os.path.splitext(form.photo.data.filename)[1] # 生成所及文件名 filename = random_string() + suffix # 保存上传文件 photos.save(form.photo.data, name=filename) # 生成缩略图 pathname = os.path.join(app.config['UPLOADED_PHOTOS_DEST'], filename) # 打开文件 img = Image.open(pathname) # 设置尺寸 img.thumbnail((128, 128)) # 保存文件 img.save(pathname) # 获取上传文件的url img_url = photos.url(filename) return render_template('upload.html', form=form, img_url=img_url)
模板文件upload.html
{% extends 'bootstrap/base.html' %} {% import 'bootstrap/wtf.html' as wtf %} {% block content %} <div class="container"> {% if img_url %} <img src="{{ img_url }}" /> {% endif %} {{ wtf.quick_form(form) }} </div> {% endblock %}
常用API
配置默认的上传文件大小: app.config['MAX_CONTENT_LENGTH'] = 8 * 1024 *1024 配置图片格式的上传文件存储路径: app.config['UPLOADED_PHOTOS_DEST'] = os.getcwd() 定义一个图片格式的上传对象: photos = UploadSet('photos', IMAGES) 保存上传对象到指定路径 filename = uploadSet.save(request.files['photo']) filename = uploadSet.save(form.filefield.data, name=form.filefield.data.filename) 获得指定文件的访问url: file_url = uploadSet.url(filename) 绑定app和uploadSet对象:configure_uploads(app, photos) 指定上传文件的大小:patch_request_class(app, size=6410241024) allowed_file(file.filename) suffix = os.path.splitext(file.filename)[1] csrf校验: app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY','123456') Bootstrap对象: bootstrap = Bootstrap(app) 创建表单: class UploadForm(FlaskForm): 文件对象: photo = FileField('photo',validators=[FileRequired('必须选择文件'),FileAllowed(photos,'必须是图片类型')]) 提交对象: submit = SubmitField('UPLOAD') 表单校验: if form.validate_on_submit(): pass 继承bootstrap: {% extends 'bootstrap/base.html' %} 引入wtf: {% import 'bootstrap/wtf.html' as wtf %} 快速集成表单: {{ wtf.quick_form(form) }}
7、Flask-Login
初始化和配置
登录管理器对象:login_manager = LoginManager(app)
动态绑定app:login_manager.init_app(app)
登录重定向路由:login_manager.login_view = ‘user.login’
定义登录的路由函数
登录重定向信息:login_manager.login_message = ‘需要登录才可访问’
登录提示信息
设置session的保护级别:login_manager.session_protection = ‘strong’
basic=默认级别
strong=加强保护
None=禁用
配置用户模型
class User(UserMixin, db.Model):
登录认证的回调
@login_manager.user_loader def load_user(uid): return User.query.get(int(uid))
返回一个用户对象(以便存取用户状态)
使用
登录(记住我)
login_user(u, remember=form.remember.data)
获取当前登录用户
current_user
当前登录用户
是否已登录:current_user.is_authenticated
是否匿名:current_user.is_anonymous
u = current_user._get_current_object()
登出
logout_user()
路由保护
@app.route('/test/') @login_required def test(): return '登录后才可访问的页面'