flask 常用扩展

  • Flask-Script
Flask-Script为Flask程序添加了一个命令行解释器,它自带了一些常用选项,还支持自定义命令  

# 安装
pip install flask-script

# 脚本
from flask.ext.script import Manager, Server  # python3中使用 from flask_script import Manager
app = Flask(__name__)
manager = Manager(app)
manager.add_command("runserver", Server(use_debugger=True))  # 开启debug
..........
if __name__ == '__main__':
    Manager.run()

# 使用
python hello.py runserver --host 0.0.0.0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • flask-bootstrap
bootstrap参考文档 http://v3.bootcss.com/

# 安装
pip install flask-bootstrap

# 脚本
from flask.ext.bootstrap import Bootstrap

app = Flask(__name__)
bootstrap = Bootstrap(app)

# 使用
{% extends "bootstrap/base.html" %}{% block title %}Flasky{% endblock %}{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
    <div class="container">  <!-- 导航条居中  -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Flasky</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
            </ul>
        </div>
    </div>
</div>
{% endblock %}{% block content %}
<div class="container">
    <div class="page-header">
        <h1>Hello!</h1>
    </div>
</div>
{% endblock %}

<!--
块  名             说  明
doc 整个             HTML 文档
html_attribs        <html> 标签的属性
html                <html> 标签中的内容
head                <head> 标签中的内容
title               <title> 标签中的内容
metas               一组 <meta> 标签
styles              层叠样式表定义
body_attribs        <body> 标签的属性
body                <body> 标签中的内容
navbar              用户定义的导航条
content             用户定义的页面内容
scripts             文档底部的 JavaScript 声明

表中的很多块都是 Flask-Bootstrap 自用的,如果直接重定义可能会导致一些问题。例
如,Bootstrap 所需的文件在 styles 和 scripts 块中声明。如果程序需要向已经有内容的块
中添加新内容,必须使用 Jinja2 提供的 super() 函数。例如,如果要在衍生模板中添加新
的 JavaScript 文件,需要这么定义 scripts 块:
{% block scripts %}{{ super() }}
<script type="text/javascript" src="my-script.js"></script>
{% endblock %}
-->
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • flask-moment
服务器需要统一时间单位,所以一般使用协调世界时(Coordinated Universal Time,UTC)。把时间单位发送给 Web 浏览器,转换成当地时间,然后渲染。
有一个使用 JavaScript 开发的优秀客户端开源代码库,名为 moment.js(http://momentjs.com/),它可以在浏览器中渲染日期和时间。Flask-Moment 是一个 Flask 程序扩展,能把moment.js 集成到 Jinja2 模板中。
# 安装
pip install flask-moment

# 脚本
from flask.ext.moment import Moment
moment = Moment(app)

@app.route('/')
def index():
    return render_template('index.html', current_time=datetime.utcnow())  # current_time供moment.js使用


base.html引入moment.js
{% block scripts %} 
{{ super() }}{{ moment.include_moment() }}  <!--引入moment.js-->
{{ moment.lang('zh-cn') }}  <!--设置语言为中文-->
{% endblock %}

index.html中使用moment.js
{% extends "base.html" %}
{% block page_content %}
<h1>Hello World!</h1>
<!--在模板中渲染moment.js-->
<p>The local date and time is {{current_time }}.</p>
<p>The local date and time is {{ moment(current_time).format('LLL') }}.</p>
<p>That was {{ moment(current_time).fromNow(refresh=True) }}</p>
{% endblock %}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • flask-wtf
Flask-WTF(http://pythonhosted.org/Flask-WTF/)扩展可以把处理 Web 表单的过程变成一种愉悦的体验。这个扩展对独立的 WTForms(http://wtforms.simplecodes.com)包进行了包装,方便集成到 Flask 程序中

# 安装
pip install flask-wtf

# 脚本
保护所有表单免受跨站请求伪造(Cross-Site Request Forgery,CSRF)的攻击
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

使用flask-bootstrap快速渲染表单
hello.py
from flask.ext.bootstrap import Bootstrap
from flask.ext.wtf import FlaskForm as BaseForm
from wtforms import StringField, SubmitField
from wtforms.validators import Required

class NameForm(BaseForm):
    name = StringField('what is your name?', validators=[Required()])
    submit = SubmitField('Submit')

@app.route('/', methods=['GET', 'POST'])  # app.route 修饰器中添加的 methods 参数告诉 Flask 在 URL 映射中把这个视图函数注册为GET 和 POST 请求的处理程序。如果没指定 methods 参数,就只把视图函数注册为 GET 请求的处理程序
def index():  # 视图函数 index() 不仅要渲染表单,还要接收表单中的数据
    form = NameForm()
    if form.validate_on_submit():  # 如果数据能被所有验证函数接受,那么 validate_on_submit() 方法的返回值为 True ,否则返回 False 。这个函数的返回值决定是重新渲染表单还是处理表单提交的数据。
        old_name = session.get('name')
        if old_name is not None and old_name != form.name.data:
            flash('Looks like you have changed your name!')  # flash() 函数在发给客户端的下一个响应中显示一个消息。仅调用 flash() 函数并不能把消息显示出来,程序使用的模板要渲染这些消息。Flask 把 get_flashed_messages() 函数开放给模板,用来获取并渲染消息
        session['name'] = form.name.data  # 程序可以把数据存储在用户会话中,在请求之间“记住”数据
        return redirect(url_for('index'))  # redirect() 是个辅助函数,用来生成 HTTP 重定向响应
    return render_template('index.html', form=form, name=session.get('name'))


index.html
{% import "bootstrap/wtf.html" as wtf %} <!--import 指令的使用方法和普通 Python 代码一样,允许导入模板中的元素并用在多个模板中-->
{{ wtf.quick_form(form) }} <!--Flask-Bootstrap 提供了一个非常高端的辅助函数,可以使用 Bootstrap 中预先定义好的表单样式渲染整个 Flask-WTF 表单-->
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • Flask-SQLAlchemy
SQLAlchemy 是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy 提供了高层 ORM,也提供了使用数据库原生 SQL 的低层功能

# 安装
pip install flask-sqlalchemy

# 配置连接
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)

basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')  # 程序使用的数据库 URL 必须保存到 Flask 配置对象的 SQLALCHEMY_DATABASE_URI 键中
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True  # SQLALCHEMY_COMMIT_ON_TEARDOWN 键,将其设为 True时,每次请求结束后都会自动提交数据库中的变动
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True  # 新版本需要加的配置
db = SQLAlchemy(app)

在 Flask-SQLAlchemy 中,数据库使用 URL 指定
数据库引擎           URL
MySQL               mysql://username:password@hostname/database
Postgres            postgresql://username:password@hostname/database
SQLite(Unix)      sqlite:////absolute/path/to/database
SQLite(Windows)   sqlite:///c:/absolute/path/to/database
Oracle              oracle://scott:tiger@127.0.0.1:1521/sidname

# 定义模型
模型这个术语表示程序使用的持久化实体。在 ORM 中,模型一般是一个 Python 类,类中的属性对应数据库表中的列
class Role(db.Model):
    __tablename__ = 'roles'  # 类变量 __tablename__ 定义在数据库中使用的表名
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)

    def __repr__(self):  #  __repr()__ 方法返回一个具有可读性的字符串表示模型
        return '<Role %r>' % self.name

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)

    def __repr__(self):
        return '<User %r>' % self.username


最常用的SQLAlchemy列类型
类型名               Python类型          说  明
Integer             int                 普通整数,一般是 32 位
SmallInteger        int                 取值范围小的整数,一般是 16 位
BigInteger          int 或 long         不限制精度的整数
Float               float               浮点数
Numeric             decimal.Decimal     定点数
String              str                 变长字符串
Text                str                 变长字符串,对较长或不限长度的字符串做了优化
Unicode             unicode             变长 Unicode 字符串
UnicodeText         unicode             变长 Unicode 字符串,对较长或不限长度的字符串做了优化
Boolean             bool                布尔值
Date                datetime.date       日期
Time                datetime.time       时间
DateTime            datetime.datetime   日期和时间
Interval            datetime.timedelta  时间间隔
Enum                str                 一组字符串
PickleType          任何 Python 对象     自动使用 Pickle 序列化
LargeBinary         str                 二进制文件


最常使用的SQLAlchemy列选项
选项名               说  明
primary_key         如果设为 True ,这列就是表的主键
unique              如果设为 True ,这列不允许出现重复的值
index               如果设为 True ,为这列创建索引,提升查询效率
nullable            如果设为 True ,这列允许使用空值;如果设为 False ,这列不允许使用空值
default             为这列定义默认值

# 关系
class Role(db.Model):
    '''
    users 属性代表这个关系的面向对象视角。对于一个 Role 类的实例,其 users 属性将返回与角色相关联的用户组成的列表。 db.relationship() 的第一个参数表明这个关系的另一端是哪个模型。如果模型类尚未定义,可使用字符串形式指定。
    db.relationship() 中的 backref 参数向 User 模型中添加一个 role 属性,从而定义反向关系。这一属性可替代 role_id 访问 Role 模型,此时获取的是模型对象,而不是外键的值.
    大多数情况下, db.relationship() 都能自行找到关系中的外键,但有时却无法决定把哪一列作为外键。例如,如果 User 模型中有两个或以上的列定义为 Role 模型的外键,SQLAlchemy 就不知道该使用哪列。如果无法决定外键,你就要为 db.relationship() 提供额外参数,从而确定所用外键.
    '''
    __tablename__ = 'roles'  # 类变量 __tablename__ 定义在数据库中使用的表名
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    users = db.relationship('User', backref='role')

    def __repr__(self):  #  __repr()__ 方法返回一个具有可读性的字符串表示模型
        return '<Role %r>' % self.name

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))  # role_id 列被定义为外键,传给 db.ForeignKey() 的参数 'roles.id' 表明,这列的值是 roles 表中行的 id 值

    def __repr__(self):
        return '<User %r>' % self.username

上面定义了'一对多'关系。一对一关系可以用前面介绍的一对多关系表示,但调用 db.relationship() 时要把 uselist 设为 False。多对一关系也可使用一对多表示,对调两个表即可,或者把外键和 db.relationship() 都放在“多”这一侧。最复杂的关系类型是多对多,需要用到第三张表,这个表称为关系表


常用的SQLAlchemy关系选项
选项名                说  明
backref              在关系的另一个模型中添加反向引用
primaryjoin          明确指定两个模型之间使用的联结条件。只在模棱两可的关系中需要指定
lazy                 指定如何加载相关记录。可选值有 select (首次访问时按需加载)、 immediate (源对象加载后就加载)、 joined (加载记录,但使用联结)、 subquery (立即加载,但使用子查询),noload (永不加载)和 dynamic (不加载记录,但提供加载记录的查询)
uselist              如果设为 Fales ,不使用列表,而使用标量值
order_by             指定关系中记录的排序方式
secondary            指定多对多关系中关系表的名字
secondaryjoin        SQLAlchemy 无法自行决定时,指定多对多关系中的二级联结条件

# 数据库操作
创建表
db.create_all()  # 如果数据库表已经存在于数据库中,那么 db.create_all()不会重新创建或者更新这个表
db.drop_all()  # 删除表

插入行
>>> from hello import Role, User
>>> admin_role = Role(name='Admin')
>>> user_john = User(username='john', role=admin_role)  # role=admin_role------>  db.relationship() 中的 backref 参数向 User 模型中添加一个 role 属性。role 属性也可使用,虽然它不是真正的数据库列,但却是一对多关系的高级表示

>>> db.session.add(admin_role)  # 或者简写成:db.session.add_all([admin_role, user_john])
>>> db.session.add(user_john)

>>> db.session.commit()

修改行
>>> admin_role.name = 'Administrator'
>>> db.session.add(admin_role)
>>> db.session.commit()

删除行
>>> db.session.delete(mod_role)
>>> db.session.commit()

回滚
db.session.rollback()

查询行
>>> Role.query.all()  # 查询所有
[<Role u'Administrator'>, <Role u'User'>]

>>> User.query.filter_by(role=admin_role).all()  # 过滤器
[<User u'john'>]

>>> str(User.query.filter_by(role=user_role))  # 查看原生sql
'SELECT users.id AS users_id, users.username AS users_username,users.role_id AS users_role_id FROM users WHERE :param_1 = users.role_id'

# 关系的查询
关系和查询的处理方式类似
>>> users = admin_role.users
>>> users
[<User u'john'>]
>>> users[0].role
<Role u'Admin'>

这个例子中的 user_role.users 查询有个小问题。执行 user_role.users 表达式时,隐含的查询会调用 all() 返回一个用户列表。 query 对象是隐藏的,因此无法指定更精确的查询过滤器
我们修改关系的设置,加入 lazy = 'dynamic' 参数,从而禁止自动执行查询
class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    users = db.relationship('User', backref='role', lazy='dynamic')

    def __repr__(self):
        return '<Role %r>' % self.name

这样配置关系之后, user_role.users 会返回一个尚未执行的查询,因此可以在其上添加过滤器:
>>> user_role.users.order_by(User.username).all()
[<User u'david'>, <User u'susan'>]
>>> user_role.users.count()
2

常用的SQLAlchemy查询过滤器
过滤器           说  明
filter()        把过滤器添加到原查询上,返回一个新查询   # User.query.filter(User.role==user_role).all()
filter_by()     把等值过滤器添加到原查询上,返回一个新查询  # User.query.filter_by(role=user_role).all()   Role.query.filter_by(name='User').all()
limit()         使用指定的值限制原查询返回的结果数量,返回一个新查询
offset()        偏移原查询返回的结果,返回一个新查询
order_by()      根据指定条件对原查询结果进行排序,返回一个新查询
group_by()      根据指定条件对原查询结果进行分组,返回一个新查询

最常使用的SQLAlchemy查询执行函数
方 法          说  明
all()           以列表形式返回查询的所有结果
first()         返回查询的第一个结果,如果没有结果,则返回 None
first_or_404()  返回查询的第一个结果,如果没有结果,则终止请求,返回 404 错误响应
get()           返回指定主键对应的行,如果没有对应的行,则返回 None
get_or_404()    返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回 404 错误响应
count()         返回查询结果的数量
paginate()      返回一个 Paginate 对象,它包含指定范围内的结果


# 继承python shell
可以在启动shell的时候自动加载db配置,导入数据库实例和模型
from flask_script import Manager, Shell

app = Flask(__name__)
manager = Manager(app)

def make_shell_context():
    return dict(app=app, db=db, User=User, Role=Role)
manager.add_command("shell", Shell(make_context=make_shell_context))

if __name__ == '__main__':
    manager.run()

启动shell: python hello.py shell
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • Flask-Mail
Flask-Mail 连接到简单邮件传输协议(Simple Mail Transfer Protocol,SMTP)服务器,并把邮件交给这个服务器发送。如果不进行配置,Flask-Mail 会连接 localhost 上的端口 25,无需验证即可发送电子邮件

# 安装
pip install flask-mail

# 脚本
import os
from flask.ext.mail import Mail
from flask.ext.mail import Message

app.config['MAIL_SERVER'] = 'smtp.163.com'  # 邮件相关配置
app.config['MAIL_PORT'] = 25
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME')  # 用户名密码配置在环境变量里面
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')
mail = Mail(app)

千万不要把账户密令直接写入脚本,特别是当你计划开源自己的作品时。为了保护账户信息,你需要让脚本从环境中导入敏感信息
保存电子邮件服务器用户名和密码的两个环境变量要在环境中定义。如果你在 Linux 或Mac OS X 中使用 bash,那么可以按照下面的方式设定这两个变量:
(venv) $ export MAIL_USERNAME=<Gmail username>
(venv) $ export MAIL_PASSWORD=<Gmail password>
微软 Windows 用户可按照下面的方式设定环境变量(注意着只是设置临时变量):
(venv) $ set MAIL_USERNAME=<Gmail username>
(venv) $ set MAIL_PASSWORD=<Gmail password>

Flask-Mail SMTP服务器的配置
配  置             默认值          说  明
MAIL_SERVER         localhost       电子邮件服务器的主机名或 IP 地址
MAIL_PORT           25              电子邮件服务器的端口
MAIL_USE_TLS        False           启用传输层安全(Transport Layer Security,TLS)协议
MAIL_USE_SSL        False           启用安全套接层(Secure Sockets Layer,SSL)协议
MAIL_USERNAME       None            邮件账户的用户名
MAIL_PASSWORD       None            邮件账户的密码

shell 中发送邮件
>>> from flask.ext.mail import Message
>>> from hello import mail
>>> msg = Message('test subject', sender='[email protected]', recipients=['[email protected]'])
>>> msg.body = 'text body'
>>> msg.html = '<b>HTML</b> body'
>>> with app.app_context():
... mail.send(msg)
...

注意,Flask-Mail 中的 send() 函数使用 current_app ,因此要在激活的程序上下文中执行。

封装成函数发送
def send_email(mail_from, mail_to, subject, template, **kwargs):
    msg = Message(subject, sender=mail_from, recipients=mail_to)
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)  #TODO: html的内容应该会覆盖body,不是很确定
    mail.send(msg)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • Werkzeug
Werkzeug 中的 security 模块能够很方便地实现密码散列值的计算

# 安装
pip install werkzeug

# 脚本
from werkzeug.security import generate_password_hash, check_password_hash

注册用户:generate_password_hash(password, method= pbkdf2:sha1, salt_length=8) :这个函数将原始密码作为输入,以字符串形式输出密码的散列值,输出的值可保存在用户数据库中。methodsalt_length 的默认值就能满足大多数需求。
验证用户:check_password_hash(hash, password):这个函数的参数是从数据库中取回的密码散列值和用户输入的密码。返回值为 True 表明密码正确。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • livereload
这个扩展可以在代码改变的时候自动重启应用,调试的时候很好用

# 安装
pip install livereload

# 脚本
from flask_script import Manager

@manager.command  # 将这个方法注册为一个命令行参数, 使用 python main.py dev 启用livereload
def dev():
    from livereload import Server  # 这个扩展可以在代码改变的时候自动重启应用,调试的时候很好用
    app.debug = True
    live_server = Server(app.wsgi_app)
    live_server.watch("**/*.*")
    # live_server.serve(open_url_delay=True)  # 这个参数可以在重启应用后在浏览器默认打开应用主页
    live_server.serve(port=5000)

if __name__ == '__main__':
    manager.run()  # 使用 python main.py runserver --host 0.0.0.0 启用
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • flask-jsonrpc
处理符合rpc格式的请求

# 安装
pip install Flask-JSONRPC==0.3.1


组织结构
project
    --common
        view.py
    --main.py


view.py
from flask import Blueprint
from flask_jsonrpc import JSONRPC

common = Blueprint("common", __name__)
common_rpc = JSONRPC(None)


@common_rpc.method("get_test_result")
def get_test_result():
    return {"abc": "abc"}


main.py
from flask import Flask
from flask_jsonrpc import JSONRPC

from common.view import common

app = Flask(__name__)
jsonrpc = JSONRPC(app, '/api')

jsonrpc.register_blueprint(common)

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)



测试代码
curl -i -X POST -H "Content-Type: application/json; indent=4" -d '{"jsonrpc": "2.0","method": "get_test_result","params": {},"id": "1"}' http://localhost:5000/api
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
转载自: https://blog.csdn.net/flyDeDog/article/details/71600458
  • Flask-Script
Flask-Script为Flask程序添加了一个命令行解释器,它自带了一些常用选项,还支持自定义命令  

# 安装
pip install flask-script

# 脚本
from flask.ext.script import Manager, Server  # python3中使用 from flask_script import Manager
app = Flask(__name__)
manager = Manager(app)
manager.add_command("runserver", Server(use_debugger=True))  # 开启debug
..........
if __name__ == '__main__':
    Manager.run()

# 使用
python hello.py runserver --host 0.0.0.0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • flask-bootstrap
bootstrap参考文档 http://v3.bootcss.com/

# 安装
pip install flask-bootstrap

# 脚本
from flask.ext.bootstrap import Bootstrap

app = Flask(__name__)
bootstrap = Bootstrap(app)

# 使用
{% extends "bootstrap/base.html" %}{% block title %}Flasky{% endblock %}{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
    <div class="container">  <!-- 导航条居中  -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Flasky</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
            </ul>
        </div>
    </div>
</div>
{% endblock %}{% block content %}
<div class="container">
    <div class="page-header">
        <h1>Hello!</h1>
    </div>
</div>
{% endblock %}

<!--
块  名             说  明
doc 整个             HTML 文档
html_attribs        <html> 标签的属性
html                <html> 标签中的内容
head                <head> 标签中的内容
title               <title> 标签中的内容
metas               一组 <meta> 标签
styles              层叠样式表定义
body_attribs        <body> 标签的属性
body                <body> 标签中的内容
navbar              用户定义的导航条
content             用户定义的页面内容
scripts             文档底部的 JavaScript 声明

表中的很多块都是 Flask-Bootstrap 自用的,如果直接重定义可能会导致一些问题。例
如,Bootstrap 所需的文件在 styles 和 scripts 块中声明。如果程序需要向已经有内容的块
中添加新内容,必须使用 Jinja2 提供的 super() 函数。例如,如果要在衍生模板中添加新
的 JavaScript 文件,需要这么定义 scripts 块:
{% block scripts %}{{ super() }}
<script type="text/javascript" src="my-script.js"></script>
{% endblock %}
-->
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • flask-moment
服务器需要统一时间单位,所以一般使用协调世界时(Coordinated Universal Time,UTC)。把时间单位发送给 Web 浏览器,转换成当地时间,然后渲染。
有一个使用 JavaScript 开发的优秀客户端开源代码库,名为 moment.js(http://momentjs.com/),它可以在浏览器中渲染日期和时间。Flask-Moment 是一个 Flask 程序扩展,能把moment.js 集成到 Jinja2 模板中。
# 安装
pip install flask-moment

# 脚本
from flask.ext.moment import Moment
moment = Moment(app)

@app.route('/')
def index():
    return render_template('index.html', current_time=datetime.utcnow())  # current_time供moment.js使用


base.html引入moment.js
{% block scripts %} 
{{ super() }}{{ moment.include_moment() }}  <!--引入moment.js-->
{{ moment.lang('zh-cn') }}  <!--设置语言为中文-->
{% endblock %}

index.html中使用moment.js
{% extends "base.html" %}
{% block page_content %}
<h1>Hello World!</h1>
<!--在模板中渲染moment.js-->
<p>The local date and time is {{current_time }}.</p>
<p>The local date and time is {{ moment(current_time).format('LLL') }}.</p>
<p>That was {{ moment(current_time).fromNow(refresh=True) }}</p>
{% endblock %}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • flask-wtf
Flask-WTF(http://pythonhosted.org/Flask-WTF/)扩展可以把处理 Web 表单的过程变成一种愉悦的体验。这个扩展对独立的 WTForms(http://wtforms.simplecodes.com)包进行了包装,方便集成到 Flask 程序中

# 安装
pip install flask-wtf

# 脚本
保护所有表单免受跨站请求伪造(Cross-Site Request Forgery,CSRF)的攻击
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

使用flask-bootstrap快速渲染表单
hello.py
from flask.ext.bootstrap import Bootstrap
from flask.ext.wtf import FlaskForm as BaseForm
from wtforms import StringField, SubmitField
from wtforms.validators import Required

class NameForm(BaseForm):
    name = StringField('what is your name?', validators=[Required()])
    submit = SubmitField('Submit')

@app.route('/', methods=['GET', 'POST'])  # app.route 修饰器中添加的 methods 参数告诉 Flask 在 URL 映射中把这个视图函数注册为GET 和 POST 请求的处理程序。如果没指定 methods 参数,就只把视图函数注册为 GET 请求的处理程序
def index():  # 视图函数 index() 不仅要渲染表单,还要接收表单中的数据
    form = NameForm()
    if form.validate_on_submit():  # 如果数据能被所有验证函数接受,那么 validate_on_submit() 方法的返回值为 True ,否则返回 False 。这个函数的返回值决定是重新渲染表单还是处理表单提交的数据。
        old_name = session.get('name')
        if old_name is not None and old_name != form.name.data:
            flash('Looks like you have changed your name!')  # flash() 函数在发给客户端的下一个响应中显示一个消息。仅调用 flash() 函数并不能把消息显示出来,程序使用的模板要渲染这些消息。Flask 把 get_flashed_messages() 函数开放给模板,用来获取并渲染消息
        session['name'] = form.name.data  # 程序可以把数据存储在用户会话中,在请求之间“记住”数据
        return redirect(url_for('index'))  # redirect() 是个辅助函数,用来生成 HTTP 重定向响应
    return render_template('index.html', form=form, name=session.get('name'))


index.html
{% import "bootstrap/wtf.html" as wtf %} <!--import 指令的使用方法和普通 Python 代码一样,允许导入模板中的元素并用在多个模板中-->
{{ wtf.quick_form(form) }} <!--Flask-Bootstrap 提供了一个非常高端的辅助函数,可以使用 Bootstrap 中预先定义好的表单样式渲染整个 Flask-WTF 表单-->
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • Flask-SQLAlchemy
SQLAlchemy 是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy 提供了高层 ORM,也提供了使用数据库原生 SQL 的低层功能

# 安装
pip install flask-sqlalchemy

# 配置连接
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)

basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')  # 程序使用的数据库 URL 必须保存到 Flask 配置对象的 SQLALCHEMY_DATABASE_URI 键中
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True  # SQLALCHEMY_COMMIT_ON_TEARDOWN 键,将其设为 True时,每次请求结束后都会自动提交数据库中的变动
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True  # 新版本需要加的配置
db = SQLAlchemy(app)

在 Flask-SQLAlchemy 中,数据库使用 URL 指定
数据库引擎           URL
MySQL               mysql://username:password@hostname/database
Postgres            postgresql://username:password@hostname/database
SQLite(Unix)      sqlite:////absolute/path/to/database
SQLite(Windows)   sqlite:///c:/absolute/path/to/database
Oracle              oracle://scott:tiger@127.0.0.1:1521/sidname

# 定义模型
模型这个术语表示程序使用的持久化实体。在 ORM 中,模型一般是一个 Python 类,类中的属性对应数据库表中的列
class Role(db.Model):
    __tablename__ = 'roles'  # 类变量 __tablename__ 定义在数据库中使用的表名
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)

    def __repr__(self):  #  __repr()__ 方法返回一个具有可读性的字符串表示模型
        return '<Role %r>' % self.name

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)

    def __repr__(self):
        return '<User %r>' % self.username


最常用的SQLAlchemy列类型
类型名               Python类型          说  明
Integer             int                 普通整数,一般是 32 位
SmallInteger        int                 取值范围小的整数,一般是 16 位
BigInteger          int 或 long         不限制精度的整数
Float               float               浮点数
Numeric             decimal.Decimal     定点数
String              str                 变长字符串
Text                str                 变长字符串,对较长或不限长度的字符串做了优化
Unicode             unicode             变长 Unicode 字符串
UnicodeText         unicode             变长 Unicode 字符串,对较长或不限长度的字符串做了优化
Boolean             bool                布尔值
Date                datetime.date       日期
Time                datetime.time       时间
DateTime            datetime.datetime   日期和时间
Interval            datetime.timedelta  时间间隔
Enum                str                 一组字符串
PickleType          任何 Python 对象     自动使用 Pickle 序列化
LargeBinary         str                 二进制文件


最常使用的SQLAlchemy列选项
选项名               说  明
primary_key         如果设为 True ,这列就是表的主键
unique              如果设为 True ,这列不允许出现重复的值
index               如果设为 True ,为这列创建索引,提升查询效率
nullable            如果设为 True ,这列允许使用空值;如果设为 False ,这列不允许使用空值
default             为这列定义默认值

# 关系
class Role(db.Model):
    '''
    users 属性代表这个关系的面向对象视角。对于一个 Role 类的实例,其 users 属性将返回与角色相关联的用户组成的列表。 db.relationship() 的第一个参数表明这个关系的另一端是哪个模型。如果模型类尚未定义,可使用字符串形式指定。
    db.relationship() 中的 backref 参数向 User 模型中添加一个 role 属性,从而定义反向关系。这一属性可替代 role_id 访问 Role 模型,此时获取的是模型对象,而不是外键的值.
    大多数情况下, db.relationship() 都能自行找到关系中的外键,但有时却无法决定把哪一列作为外键。例如,如果 User 模型中有两个或以上的列定义为 Role 模型的外键,SQLAlchemy 就不知道该使用哪列。如果无法决定外键,你就要为 db.relationship() 提供额外参数,从而确定所用外键.
    '''
    __tablename__ = 'roles'  # 类变量 __tablename__ 定义在数据库中使用的表名
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    users = db.relationship('User', backref='role')

    def __repr__(self):  #  __repr()__ 方法返回一个具有可读性的字符串表示模型
        return '<Role %r>' % self.name

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))  # role_id 列被定义为外键,传给 db.ForeignKey() 的参数 'roles.id' 表明,这列的值是 roles 表中行的 id 值

    def __repr__(self):
        return '<User %r>' % self.username

上面定义了'一对多'关系。一对一关系可以用前面介绍的一对多关系表示,但调用 db.relationship() 时要把 uselist 设为 False。多对一关系也可使用一对多表示,对调两个表即可,或者把外键和 db.relationship() 都放在“多”这一侧。最复杂的关系类型是多对多,需要用到第三张表,这个表称为关系表


常用的SQLAlchemy关系选项
选项名                说  明
backref              在关系的另一个模型中添加反向引用
primaryjoin          明确指定两个模型之间使用的联结条件。只在模棱两可的关系中需要指定
lazy                 指定如何加载相关记录。可选值有 select (首次访问时按需加载)、 immediate (源对象加载后就加载)、 joined (加载记录,但使用联结)、 subquery (立即加载,但使用子查询),noload (永不加载)和 dynamic (不加载记录,但提供加载记录的查询)
uselist              如果设为 Fales ,不使用列表,而使用标量值
order_by             指定关系中记录的排序方式
secondary            指定多对多关系中关系表的名字
secondaryjoin        SQLAlchemy 无法自行决定时,指定多对多关系中的二级联结条件

# 数据库操作
创建表
db.create_all()  # 如果数据库表已经存在于数据库中,那么 db.create_all()不会重新创建或者更新这个表
db.drop_all()  # 删除表

插入行
>>> from hello import Role, User
>>> admin_role = Role(name='Admin')
>>> user_john = User(username='john', role=admin_role)  # role=admin_role------>  db.relationship() 中的 backref 参数向 User 模型中添加一个 role 属性。role 属性也可使用,虽然它不是真正的数据库列,但却是一对多关系的高级表示

>>> db.session.add(admin_role)  # 或者简写成:db.session.add_all([admin_role, user_john])
>>> db.session.add(user_john)

>>> db.session.commit()

修改行
>>> admin_role.name = 'Administrator'
>>> db.session.add(admin_role)
>>> db.session.commit()

删除行
>>> db.session.delete(mod_role)
>>> db.session.commit()

回滚
db.session.rollback()

查询行
>>> Role.query.all()  # 查询所有
[<Role u'Administrator'>, <Role u'User'>]

>>> User.query.filter_by(role=admin_role).all()  # 过滤器
[<User u'john'>]

>>> str(User.query.filter_by(role=user_role))  # 查看原生sql
'SELECT users.id AS users_id, users.username AS users_username,users.role_id AS users_role_id FROM users WHERE :param_1 = users.role_id'

# 关系的查询
关系和查询的处理方式类似
>>> users = admin_role.users
>>> users
[<User u'john'>]
>>> users[0].role
<Role u'Admin'>

这个例子中的 user_role.users 查询有个小问题。执行 user_role.users 表达式时,隐含的查询会调用 all() 返回一个用户列表。 query 对象是隐藏的,因此无法指定更精确的查询过滤器
我们修改关系的设置,加入 lazy = 'dynamic' 参数,从而禁止自动执行查询
class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    users = db.relationship('User', backref='role', lazy='dynamic')

    def __repr__(self):
        return '<Role %r>' % self.name

这样配置关系之后, user_role.users 会返回一个尚未执行的查询,因此可以在其上添加过滤器:
>>> user_role.users.order_by(User.username).all()
[<User u'david'>, <User u'susan'>]
>>> user_role.users.count()
2

常用的SQLAlchemy查询过滤器
过滤器           说  明
filter()        把过滤器添加到原查询上,返回一个新查询   # User.query.filter(User.role==user_role).all()
filter_by()     把等值过滤器添加到原查询上,返回一个新查询  # User.query.filter_by(role=user_role).all()   Role.query.filter_by(name='User').all()
limit()         使用指定的值限制原查询返回的结果数量,返回一个新查询
offset()        偏移原查询返回的结果,返回一个新查询
order_by()      根据指定条件对原查询结果进行排序,返回一个新查询
group_by()      根据指定条件对原查询结果进行分组,返回一个新查询

最常使用的SQLAlchemy查询执行函数
方 法          说  明
all()           以列表形式返回查询的所有结果
first()         返回查询的第一个结果,如果没有结果,则返回 None
first_or_404()  返回查询的第一个结果,如果没有结果,则终止请求,返回 404 错误响应
get()           返回指定主键对应的行,如果没有对应的行,则返回 None
get_or_404()    返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回 404 错误响应
count()         返回查询结果的数量
paginate()      返回一个 Paginate 对象,它包含指定范围内的结果


# 继承python shell
可以在启动shell的时候自动加载db配置,导入数据库实例和模型
from flask_script import Manager, Shell

app = Flask(__name__)
manager = Manager(app)

def make_shell_context():
    return dict(app=app, db=db, User=User, Role=Role)
manager.add_command("shell", Shell(make_context=make_shell_context))

if __name__ == '__main__':
    manager.run()

启动shell: python hello.py shell
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • Flask-Mail
Flask-Mail 连接到简单邮件传输协议(Simple Mail Transfer Protocol,SMTP)服务器,并把邮件交给这个服务器发送。如果不进行配置,Flask-Mail 会连接 localhost 上的端口 25,无需验证即可发送电子邮件

# 安装
pip install flask-mail

# 脚本
import os
from flask.ext.mail import Mail
from flask.ext.mail import Message

app.config['MAIL_SERVER'] = 'smtp.163.com'  # 邮件相关配置
app.config['MAIL_PORT'] = 25
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME')  # 用户名密码配置在环境变量里面
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')
mail = Mail(app)

千万不要把账户密令直接写入脚本,特别是当你计划开源自己的作品时。为了保护账户信息,你需要让脚本从环境中导入敏感信息
保存电子邮件服务器用户名和密码的两个环境变量要在环境中定义。如果你在 Linux 或Mac OS X 中使用 bash,那么可以按照下面的方式设定这两个变量:
(venv) $ export MAIL_USERNAME=<Gmail username>
(venv) $ export MAIL_PASSWORD=<Gmail password>
微软 Windows 用户可按照下面的方式设定环境变量(注意着只是设置临时变量):
(venv) $ set MAIL_USERNAME=<Gmail username>
(venv) $ set MAIL_PASSWORD=<Gmail password>

Flask-Mail SMTP服务器的配置
配  置             默认值          说  明
MAIL_SERVER         localhost       电子邮件服务器的主机名或 IP 地址
MAIL_PORT           25              电子邮件服务器的端口
MAIL_USE_TLS        False           启用传输层安全(Transport Layer Security,TLS)协议
MAIL_USE_SSL        False           启用安全套接层(Secure Sockets Layer,SSL)协议
MAIL_USERNAME       None            邮件账户的用户名
MAIL_PASSWORD       None            邮件账户的密码

shell 中发送邮件
>>> from flask.ext.mail import Message
>>> from hello import mail
>>> msg = Message('test subject', sender='[email protected]', recipients=['[email protected]'])
>>> msg.body = 'text body'
>>> msg.html = '<b>HTML</b> body'
>>> with app.app_context():
... mail.send(msg)
...

注意,Flask-Mail 中的 send() 函数使用 current_app ,因此要在激活的程序上下文中执行。

封装成函数发送
def send_email(mail_from, mail_to, subject, template, **kwargs):
    msg = Message(subject, sender=mail_from, recipients=mail_to)
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)  #TODO: html的内容应该会覆盖body,不是很确定
    mail.send(msg)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • Werkzeug
Werkzeug 中的 security 模块能够很方便地实现密码散列值的计算

# 安装
pip install werkzeug

# 脚本
from werkzeug.security import generate_password_hash, check_password_hash

注册用户:generate_password_hash(password, method= pbkdf2:sha1, salt_length=8) :这个函数将原始密码作为输入,以字符串形式输出密码的散列值,输出的值可保存在用户数据库中。methodsalt_length 的默认值就能满足大多数需求。
验证用户:check_password_hash(hash, password):这个函数的参数是从数据库中取回的密码散列值和用户输入的密码。返回值为 True 表明密码正确。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • livereload
这个扩展可以在代码改变的时候自动重启应用,调试的时候很好用

# 安装
pip install livereload

# 脚本
from flask_script import Manager

@manager.command  # 将这个方法注册为一个命令行参数, 使用 python main.py dev 启用livereload
def dev():
    from livereload import Server  # 这个扩展可以在代码改变的时候自动重启应用,调试的时候很好用
    app.debug = True
    live_server = Server(app.wsgi_app)
    live_server.watch("**/*.*")
    # live_server.serve(open_url_delay=True)  # 这个参数可以在重启应用后在浏览器默认打开应用主页
    live_server.serve(port=5000)

if __name__ == '__main__':
    manager.run()  # 使用 python main.py runserver --host 0.0.0.0 启用
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • flask-jsonrpc
处理符合rpc格式的请求

# 安装
pip install Flask-JSONRPC==0.3.1


组织结构
project
    --common
        view.py
    --main.py


view.py
from flask import Blueprint
from flask_jsonrpc import JSONRPC

common = Blueprint("common", __name__)
common_rpc = JSONRPC(None)


@common_rpc.method("get_test_result")
def get_test_result():
    return {"abc": "abc"}


main.py
from flask import Flask
from flask_jsonrpc import JSONRPC

from common.view import common

app = Flask(__name__)
jsonrpc = JSONRPC(app, '/api')

jsonrpc.register_blueprint(common)

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)



测试代码
curl -i -X POST -H "Content-Type: application/json; indent=4" -d '{"jsonrpc": "2.0","method": "get_test_result","params": {},"id": "1"}' http://localhost:5000/api
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/flyDeDog/article/details/71600458

猜你喜欢

转载自www.cnblogs.com/ray-mr-huang/p/9126150.html