使用扩展增强Flask功能

Flask自身仅包含非常核心的功能,其更加强大的功能是由扩展来提供的。以下选择几个常用的扩展进行介绍,更加丰富的扩展列表可以在Flask Extensions找到。

扩展一般都命名为Flask-ExtName或者ExtName-Flask的形式。要使用一个扩展,可以直接在主启动文件(Flask实例初始化的文件)中通过传入Flask实例来完成扩展的载入和实例化。例如:

from flask-foo import Foo

foo = Foo()
app = Flask(__name__)

foo.init_app(app)

常用的Flask扩展有以下这些,其具体用法可以参考其文档。

  • Flask-SQLAlchemy:SQLAlchemy的Flask扩展,允许在Flask中便捷的使用SQLAlchemy。
  • Flask-WTF:提供了WTForms的接入,允许以简便的方法处理表单。
  • Flask-Peewee:提供Peewee ORM的接入。
  • Flask-OAtuh:提供了OAuth的支持。
  • Flask-Mail:提供了比较简单的发送邮件的支持。
  • Flask-Mako:允许使用Mako模板引擎来替代Jinja2。
  • Flask-Login:提供Flask对于用户Session的管理,支持用户的登入、登出以及会话记录等功能。
  • Flask-HTTPAuth:提供了Flask对于HTTP Header认证的支持。
  • Flask-Security:提供简单易用的安全与验证功能。
  • Flask-SSE:提供了Server Send Events的支持。
  • Flask-XML-RPC:提供了XML-RPC的支持。
  • Flask-Celery:提供了Celery的接入。
  • Flask-Bcrypt:提供了Bcrypt加密、散列功能支持。
  • Flask-SocketIO:提供了WebSocket功能的支持。
  • Flask-PageDown:提供了PageDown的包装,用于将Markdown转换为HTML。
  • Flask-KVsession:使用服务器端存储实现的用户Session。
  • Flask-Assets:用于合并、压缩、编译CSS和Javascript等静态资源文件。
  • Falsk-ApScheduler:定时任务框架。
  • Flask_nameko:用于在Flask中使用Nameko微服务。

Flask-SQLAlchemy

SQLAlchemy是Python中常用的ORM框架,Flask提供了一个扩展来允许用户更加便捷的在Flask应用中使用SQLAlchemy。Flask-SQLAlchemy主要提供了随着Flask实例启动数据库连接和关闭数据库连接的功能,其中数据表映射定义及查询等功能都没有任何变化,唯一的变化可能是不再需要引入sqlalchemy.orm

以下示例引入了Flask-SQLAlchemy,并将其载入了Flask实例。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////temp/test.db'
db = SQLAlchemy(app)

从示例中可以看出,Flask-SQLAlchemy是通过app.config['SQLALCHEMY_DATABASE_URI']来指定要连接的数据库内容的,所以可以在配置文件中将此配置项写入以便不在代码中进行硬编码。之后整个应用中的数据库操作均可以通过db来完成,其中数据表映射定义要使用的Column()等方法,均已包含在db中,可以直接使用。

对于使用类来进行数据表映射,之前独立使用SQLAlchemy时需要先建立一个Base基类,这项工作在Flask-SQLAlchemy中已经完成,可以直接继承db.Model类即可。

Flask-SQLAlchemy常用的配置项有:

  • SQLALCHEMY_DATABASE_URI,指定SQLAlchemy要连接的数据库URI,格式与SQLAlchemy中连接串格式相同。
  • SQLALCHEMY_ECHO,在SQL语句出现错误时,是否输出全部SQL语句。
  • SQLALCHEMY_POOL_SIZE,指定数据库连接池的大小。
  • SQLALCHEMY_POOL_TIMEOUT,指定数据库连接池中连接的超时时间,单位是秒。
  • SQLALCHEMY_POOL_RECYCLE,指定数据库连接池中连接的空闲回收时间,当空闲超过本时间后,连接即被关闭回收,单位是秒。
  • SQLALCHEMY_MAX_OVERFLOW,指定当数据库连接池连接数达到指定大小时,还可以创建的最大连接数。

对于数据表的查询可以直接使用实体来完成,增删改可以借助db.session来完成,这部分操作与SQLAlchemy中的操作完全一致。

在Restful Web应用中,常常会以JSON格式输出数据内容,但是如果直接使用jsonify()对SQLAlchemy查询结果进行序列化时,往往会得到XXX is not JSON serializable的错误,这是因为SQLAlchemy返回的实体是一个复杂结构,并不能简单的转换为字典等简单数据类型。要完成SQLAlchemy实体向字典类型的转换,推荐采用marshmallow库,具体使用可参考相应章节的介绍。

Flask-SocketIO

Flask本身不带WebSocket的实现,如果要在Flask框架上使用WebSocket功能,需要使用Flask-SocketIO扩展来完成。在客户端可以使用socket.io库来完成功能对接。

Flask-SocketIO的初始化十分简单,而且与Flask-SQLAlchemy基本相似。

from flask import Flask
from flask_socketio import SokcetIO

app = Flask(__name__)
app.config['SECRET_KEY'] = b'key'
socketio = SocketIO(app)

Flask-SocketIO通过修饰器来设定相应WebSocket事件的处理函数。@socketio.on(param)可以用来接收命名事件与未命名事件的信息。如果param的值为'message'则被修饰的处理函数可以接受未命名事件,并将其发送的内容作为参数收集起来;如果param的值为'json',则可以使用JSON解析客户端发送的未命名事件。

如果在@socketio.on(param)中传入一个自定义的事件名称,则处理函数就会响应带有自定义事件的请求。所有类型的处理函数都可以接受多个参数。此外,@socketio.on(param)还可以接受一个额外的命名参数namespace,指定不同的namespace可以允许客户端与WebSocket之间建立多条独立连接。

WebSocket是双向通讯的,所以Flask-SocketIO也同样支持消息的发送。消息发送功能是通过Flask-SocketIO提供的send()emit()两个函数完成的。其中send()函数用来发送未命名事件,emit()用来发送命名事件。两个函数的使用格式基本一致,其中emit()的第一个参数为事件名称,第二个参数为消息内容,并且支持发送多个消息内容;而send()函数由于是发送未命名事件,所以其参数直接为消息内容。两个参数都可以接一个名称为namespace的参数,这可以允许两个函数将消息发送至指定的命名空间(连接)中。

在默认情况下,send()emit()都是与客户端一对一进行消息收发操作的,如果服务器需要群发通知,则需要给这两个函数添加一个命名参数broadcast=True,这就表示本次消息发送为广播发送,所有已连接的客户端都会收到消息。

下面给出Flask-SocketIO的一些常用修饰器及响应事件的标识。

  • @socketio.on(event, namespace='/'),用于对客户端发送数据进行响应。
    • 'message',未命名事件,直接获取数据。
    • 'json',未命名事件,以JSON格式解析数据。
    • 'custom event',命名事件,可以接受任意类型数据。
    • 'connect',客户端连接事件。
    • 'disconnect',客户端断开事件。
    • 'join',客户端加入群事件。
    • 'leave',客户端离开群事件。
  • @socketio.on_error(),用于响应默认命名空间内的错误,指定命名空间后响应指定命名空间的错误。
  • @socketio.on_error_default,用于响应所有命名空间内的错误。

其他更多的使用方式可参考Flask-SocketIO的文档。

Flask-Script

Flask-Script扩展向Flask提供了插入外部脚本的功能,常用功能主要有以下几个。

  • 运行一个开发用的服务器。
  • 运行一个定制的Python Shell。
  • 设置数据库。
  • 定时任务。
  • 运行Web应用之外的命令。

在很多线上教程的示例中,都会出现一个专门用于管理Flask站点的manager.py,并且一般通过这个文件来完成Flask运行实例的管理。这个文件可以通过Flask-Script来实现功能。

Warning

注意,在0.11版之后的Flask中内置的CLI命令行工具已经能够完全替代Flask-Script了,所以在大部分情况下还请使用Flask内置的CLI工具来实现应用管理脚本。

Manager类

Flask-Script提供了一个Manager类,可以使用它来管理一个Flask实例。其最简单的使用示例如下。

from flask_script import Manager
from app import app


manager = Manager(app)


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

在这个最简单的示例中,只需要执行python manager.py即可启动Manager实例并运行Flask应用实例。Manager实例还可以接受命令行命令来完成额外的功能。在Flask-Script中,命令的定义有三种方式。

  • 创建Command子类,实现其中的run()方法,并使用Manageradd_command()方法将其添加到Manager实例中。
  • 使用@manager.command修饰器修饰一个函数,函数名即可成为一个命令。
  • 使用@manager.option()修饰器修饰一个函数,函数名即可成为一个命令,并且可以接受参数。一个函数可以被多个@manager.option()修饰器修饰。

以下给出一个详细的使用示例。

from flask_script import Manager
from app import create_app


manager = Manager(create_app)


@manager.option('-n', '--name', dest='name', help='App name', default='APP')
@manager.option('-p', '--port', dest='port', default=8080)
def start(name, port):
	print(name)
	print(port)


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

在这个示例中,dest='name'指定了这个Option修饰器定义的参数对应的函数参数名称,并且可以在执行命令python manager.py start -n MyApp时将参数传入函数进行处理。

Manager实例可以通过add_command()方法嵌套使用,以形成一套复杂的命令行控制。

Server类

Server类是Flask-Script中提供的开发服务器。Server类一般会提供一个默认的命令和配置。以下给出一个常见的使用方法。

from flask_script import Server, Manager
from app import create_app


manager = Manager(create_app)
server = Server(host='0.0.0.0', port=9000)
manager.add_command('runserver', server)


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

当在命令行中执行python manager.py runserver时,便会按照配置启动Flask应用。

Flask_Nameko

Flask_Nameko用于在Flask中对Nameko微服务进行包装。Flask_Nameko可以通过命令pip install flask_nameko完成安装。

要使用Flask_Nameko,需要在Flask app中对Nameko进行初始化,Flask_Nameko提供了一个FlaskPooledClusterRpcProxy类来与Nameko的RPC服务集群进行通信。初始化过程一般可以参考以下示例。

from flask import Flask
from flask_nameko import FlaskPooledClusterRpcProxy


rpc = FlaskPooledClusterRpcProxy()

def create_app():
	app = Flask(__name__)
	
	rpc.init_app(app)

app = create_app()

之后在需要调用RPC服务的位置就可以如以下示例中一般使用。

from . import app, rpc


@app.route('/')
def index():
	result = rpc.service.some_method('some_value')
	return result

FlaskPooledClusterRpcProxy可以接受所有Nameko中的配置项,但前面需要添加NAMEKO_前缀。除Nameko定义的配置项以外,Flask_Nameko还定义了以下配置项供使用。

  • NAMEKO_INITIAL_CONNECTIONS,初始创建的连接数量,默认为2。
  • NAMEKO_MAX_CONNECTIONS,最大创建的连接数量,默认为8。
  • NAMEKO_CONNECT_ON_METHOD_CALL,决定何时加载连接到服务的连接,False表示在连接到服务时,True表示调用RPC方法时。
  • NAMEKO_RPC_TIMEOUT,调用RPC方法的默认超时时间。
  • NAMEKO_POOL_RECYCLE,连接池连接回收的秒数,连接大于指定秒数的将被自动回收。