FlaskBB阅读笔记(一)
开篇¶
FlaskBB是用Flask框架实现的一个轻量级的论坛社区软件,代码托管在GitHub上。本系列文章通过阅读FlaskBB的源代码来深入学习Flask框架,以及在一个产品级的Flask应用里的一些最佳实践规则。
本文是这系列文章的第一遍。本文分析FlaskBB的主程序app.py
的源码。我们从create_app()
函数入手,分析FlaskBB的软件结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
配置¶
FlaskBB使用下面典型的配置代码了加载应用程序的配置信息。
1 2 3 4 5 6 |
|
Flask.config
类是专门用来处理应用程序全局配置信息的。它类似python的dict
类,增加了一些导入配置的函数而已。其中Flask.config.from_object()
用来从一个python类里导入配置信息,需要注意的是,这个函数只导入大写的类成员变量,小写的类成员函数是不导入的。
Flask.config.from_envvar()
用来从环境变量指定的文件中导入设置信息,比如上例中,可以设置FLASKBB_SETTINGS
的环境变量指向/path/to/python/config/file.py,这样程序就会从这个文件里导入配置信息。
需要注意的是,最后导入的配置信息可覆盖前面导入的信息。所以,一般会有三个层次:一是默认配置;二是应用程序创建时传入的参数;最后再从环境变量里导入。
FlaskBB提供了不少配置信息,比如SEND_LOGS
表示是不是要把错误信息发送给网站管理员邮箱;SQLALCHEMY_DATABASE_URI
表示ORM数据库路径等等。具体参阅flaskbb.configs.default.DefaultConfig
类。
Blueprint¶
Blueprint是Flask提供的模块化设计组件。FlaskBB通过configure_blueprints()
来初始化Blueprint
1 2 3 4 5 |
|
主要由四个Blueprint组成:
- forum
论坛主模块,由
flaskbb.forum.views.forum
Blueprint实现,默认其挂载的URL是/
- user
用户管理模块,由
flaskbb.user.views.user
Blueprint实现,默认其挂载的URL是/user
- auth
鉴权模块,由
flaskbb.auth.views.auth
Blueprint实现,默认其挂载的URL是/auth
- management
后台管理模块,由
flaskbb.management.views.management
Blueprint实现,默认其挂载的URL是/admin
FlaskBB用到的Flask扩展¶
有大量的第三方开发者为Flask构架开发扩展,在这里可以找到官方收录的所有Flask扩展。FlaskBB通过configure_extensions()
函数来初始化用到的扩展。这些扩展的简要信息汇总如下:
- Flask-SQLAlchemy 这是sqlalchemy的Flask扩展,提供SQL数据库和ORM访问。
- Flask-Login 这个扩展提供了用户会话管理。实现了一些通用的会话管理任务,如登录,登出,以及记录用户会话期间的状态数据等。
- [Flask-Mail][5] 这个扩展让Flask应用很容易地发送电子邮件,而且支持单元测试。
- Flask-Cache 给Flask程序提供Cache支持。
- Flask-DebugToolbar 从Django移植过来的适用于Flask的调试器。主要用来调试Flask程序及性能。
- Flask-Redis 给Flask程序添加Redis的扩展。Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
- Flask-Migrate 给Flask用的SQLAlchemy数据库迁移工具。比如,Flask应用的1.3版本在1.2版本的数据库的某个表里添加了一个字段,那么使用这个工具可以自动生成数据库迁移脚本,帮助使用1.2版本的用户把数据库从1.2版本升级到1.3版本。
- Flask-Theme2 给Flask应用添加主题支持。
- Flask-Plugins 和FlaskBB的作者是同一个人。提供更简单的插件管理。
- Flask-WhooshAlchemy 这个扩展帮助Flask程序实现基于SQLAlchemy数据库内容的文本搜索和索引服务。正如扩展的名字,它是使用whoosh和SQLAlchemy的ORM结合起来实现广西内容的搜索和索引功能。
- Flask-WTF 当你必须处理浏览器提交的表单数据时,视图代码很快会变得难以阅读。有一些库可以简化这个工作,其中之一便是WTForms。这个扩展让Flask使用更简单地集成WTForms,同时处理了CSRF(Cross-Site Rrequest Forgery,跨站请求伪造),提供更好的安全性。还提供文件上传等功能。
- Flask-Script
给Flask应用程序提供外部脚本支持。比如运行开发服务器,初始化数据库,等命令行相关的任务。对FlaskBB而言,
python manage.py runserver
和python manage.py createall
等命令就是通过这个扩展实现的。
自定义的Jinja2过滤器¶
Jinja2提供了自定义过滤器的功能,可以在Jinja2模板里灵活使用。FlaskBB通过函数configure_template_filters()
定义了一系列过滤器,其中is_online
过滤器是这样定义的:
app.jinja_env.filters['is_online'] = is_online
过滤器就是一个简单的python函数,is_online()
函数定义在flaskbb/utils/helper.py里:
1 2 3 4 5 6 7 |
|
这样,在Jinaja2模板flaskbb/templates/user/profile.html里,就可以使用下面的代码来判断用户是否在线:
{% if user|is_online %}
<tr><td><span class="label label-success">Online</span></td></tr>
{% else %}
<tr><td><span class="label label-default">Offline</span></td></tr>
{% endif %}
上面Jinja2模板里user|is_online
脚本会导致is_online(user)
被调用来判断用户是否在线。
向模板注入设置信息¶
FlaskBB通过调用configure_context_processors()
向模板注入设置信息。代码如下:
1 2 3 4 5 6 7 8 9 10 |
|
使用context_processor
装饰器来装饰inject_flaskbb_config()
函数,这样这个函数会被Flask记录起来,每次要渲染模板时,会先调用这个函数更新一下模板上下文信息。这样,在模板里就可以访问这里注入的上下文信息。上下文处理器函数必须返回一个dict
实例。Flask官方文档对context_processor有详细的描述。
例如,返回的dict
里包含’name: kamidox’这样的值,则在Jinja2模板里可以直接用{% name %}
来访问name
变量,其值为kamidox
。
更新用户在线信息¶
FlaskBB通过configure_before_handlers()
函数来注册每个请求之前的动作,以记录用户的在线信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
这里,before_request
装饰器将把update_lastseen()
函数注册进Flask,Flask在处理请求之前都会调用这个函数。FlaskBB使用这个机制来记录最后一次看到用户的时间。结合会话的超时机制,就可以判断用户是否在线。
自定义错误处理¶
通过configure_errorhandlers()
来实现自定义错误处理。其中,HTTP 403, 404及500的错误处理定义如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
这样当发生这些http错误时,错误网页将从服务器返回自定义的错误网页,而不是浏览器客户端默认的错误页面。
LOG配置¶
通过configure_logging()
来配置系统的LOG。FlaskBB的LOG主要保存在应用程序根目录下的logs目录里,分两个文件保存,一个是INFO级别的LOG,另外一个是ERROR级别的LOG。同时还支持把ERROR级别的LOG通过邮件的方式发送给网站管理员。
下面代码配置了INFO级别的LOG:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
下面代码配置了通过邮件发送错误LOG给网站管理员:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
结束语¶
通过对主程序app.py
的代码分析,我们基本上知道了FlaskBB的主体框架,模块划分,用到的外部扩展等信息。下一篇将分模块深入阅读各个Blueprint模块的实现以及数据库设计方面的内容。
[5]: http://github.com/mattupstate/flask-mail/