开篇
FlaskBB是用Flask框架实现的一个轻量级的论坛社区软件,代码托管在GitHub上。本系列文章通过阅读FlaskBB的源代码来深入学习Flask框架,以及在一个产品级的Flask应用里的一些最佳实践规则。
本文是这系列文章的第二遍。本文分析FlaskBB的脚本管理程序manage.py
的源码。基本上每个Flask程序都需要一个manage.py
,用户可以通过它来创建数据库,运行开发服务器的任务。在FlaskBB的README.md
里有下面一段话:
* Create a virtualenv * Install the dependencies * `pip install -r requirements.txt` * Configuration (_adjust them accordingly to your needs_) * For development copy `flaskbb/configs/development.py.example` to `flaskbb/configs/development.py` * Database creation * `python manage.py createall` * Run the development server * `python manage.py runserver` * Visit [localhost:8080](http://localhost:8080)
这些指令是指导用户安装/运行FlaskBB论坛程序的。其中python manage.py createall
和python manage.py runserver
就是本文要介绍的主角,其中第一条命令用来创建一个测试数据库,第二条命令用来运行开发服务器。
有了这些神器,从GitHub下载代码:
cd ~ git clone https://github.com/sh4nks/flaskbb.git
然后创建virtualenv:
cd ~/flaskbb virtualenv .venv source .venv/bin/activate pip install -r requirements.txt
拷贝配置文件:
cp flaskbb/configs/development.py.example flaskbb/configs/development.py
创建数据库,并运行开发服务器:
python manage.py createall python manage.py runserver
这样打开localhost:8080即可看到FlaskBB运行出来的论坛网站了。
Flask-Script用法
要了解manage.py
的工作原理,必须先了解Flask-Script扩展模块的用法。在本系列第一篇文章中,我们简要介绍了Flask-Script的作用。其官方文档这样描述自己:
The Flask-Script extension provides support for writing external scripts in Flask. This includes running a development server, a customised Python shell, scripts to set up your database, cronjobs, and other command-line tasks that belong outside the web application itself.
创建命令
使用@command
装饰器创建命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from flask.ext.script import Manager app = Flask(__name__) # configure your app manager = Manager(app) @manager.command def hello(): "Just say hello" print "hello" if __name__ == "__main__": manager.run() |
这样就创建了一个hello
的命令,假设上述文件保存为manage.py
,则可以运行这个添加的命令:
$ python manage.py hello > hello world
用@option
装饰器创建带参数的命令:
@manager.option('-n', '--name', dest='name', default='joe') @manager.option('-u', '--url', dest='url', default=None) def hello(name, url): if url is None: print "hello", name else: print "hello", name, "from", url
上述命令可以这样调用:
$ python manage.py hello -n Joe -u reddit.com > hello Joe from reddit.com $ python manage.py hello -n Joe > hello Joe $ python manage.py hello --name Joey --url kamidox.com > hello Joey from kamidox.com
实际上,使用@command
装饰器也可以实现上述相同的带参数的命令,只是使用@option
可读性更好一点。
获取用户输入
在创建数据库时,需要和用户交互,输入数据库用户名密码等信息。我们可以借助prompt系列函数来获取用户的输入:
1 2 3 4 5 6 7 8 9 10 11 |
from flask.ext.script import Manager, prompt_bool from myapp import app from myapp.models import db manager = Manager(app) @manager.command def dropdb(): if prompt_bool("Are you sure you want to lose all your data"): db.drop_all() |
这个命令可以这样调用:
$ python manage.py dropdb > Are you sure you want to lose all your data ? [N]
Flask-Script还提供了prompt_pass()
,prompt_choices()
等不同形态的函数来获取用户输入信息。
其它技巧
不带任何参数运行python manage.py
会输出可用的命令列表:
(.venv)kamidox@kamidox-laptop:~/code/flaskbb$ python manage.py usage: manage.py [-?] {shell,create_admin,db,createall,runserver,initflaskbb,initdb,dropdb} ... positional arguments: {shell,create_admin,db,createall,runserver,initflaskbb,initdb,dropdb} shell Runs a Python shell inside Flask application context. create_admin Creates the admin user db Perform database migrations createall Creates the database with some testing content. If you do not want to drop or create the db add '-c' (to not create the db) and '-d' (to not drop the db) runserver Runs the Flask development server i.e. app.run() initflaskbb Initializes FlaskBB with all necessary data initdb Creates the database. dropdb Deletes the database optional arguments: -?, --help show this help message and exit
也可以针对特定命令获取其帮助信息:
(.venv)kamidox@kamidox-laptop:~/code/flaskbb$ python manage.py runserver --help usage: manage.py runserver [-?] [-h HOST] [-p PORT] [--threaded] [--processes PROCESSES] [--passthrough-errors] [-d] [-D] [-r] [-R] Runs the Flask development server i.e. app.run() optional arguments: -?, --help show this help message and exit -h HOST, --host HOST -p PORT, --port PORT --threaded --processes PROCESSES --passthrough-errors -d, --debug enable the Werkzeug debugger (DO NOT use in production code) -D, --no-debug disable the Werkzeug debugger -r, --reload monitor Python files for changes (not 100{'const': True, 'help': 'monitor Python files for changes (not 100% safe for production use)', 'option_strings': ['-r', '--reload'], 'dest': 'use_reloader', 'required': False, 'nargs': 0, 'choices': None, 'default': None, 'prog': 'manage.py runserver', 'container': <argparse._ArgumentGroup object at 0xb609cd6c>, 'type': None, 'metavar': None}afe for production use) -R, --no-reload do not monitor Python files for changes
更多详细的用法可参阅Flask-Script官方文档,如果翻墙不便,也可以从GitHub上下载Flask-Script源码,然后在docs自己编译生成html文档。
cd ~/code git clone https://github.com/smurfix/flask-script.git cd docs make html
编译完成后,打开docs/_build/html/index.html
即可查阅Flask-Script文档了。
Sphinx
如果编译提示出错,检查一下是否安装了Sphinx。这是个用来生成优美的html文档的引擎。IBM DeveloperWorks有一篇文章介绍了Sphinx的作用。感兴趣的朋友可以参考一下。
manage.py源码分析
有了上面的背景知识,阅读manage.py
就很轻松了。
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 |
@manager.option('-u', '--username', dest='username') @manager.option('-p', '--password', dest='password') @manager.option('-e', '--email', dest='email') def initflaskbb(username=None, password=None, email=None): """Initializes FlaskBB with all necessary data""" app.logger.info("Creating default data...") try: create_default_groups() create_default_settings() except IntegrityError: app.logger.error("Couldn't create the default data because it already " "exist!") if prompt_bool("Do you want to recreate the database? (y/n)"): db.session.rollback() db.drop_all() db.create_all() create_default_groups() create_default_settings() else: sys.exit(0) except OperationalError: app.logger.error("No database found.") if prompt_bool("Do you want to create the database now? (y/n)"): db.session.rollback() db.create_all() create_default_groups() create_default_settings() else: sys.exit(0) app.logger.info("Creating admin user...") if username and password and email: create_admin_user(username=username, password=password, email=email) else: create_admin() app.logger.info("Creating welcome forum...") create_welcome_forum() app.logger.info("Congratulations! FlaskBB has been successfully installed") |
上面是manage.py
里initflaskbb
命令的代码。
- Line 1-4: 声明了
initflaskbb
命令,并且带三个参数,分别是username
,password
,email
用来创建管理员用户 - Line 9-10: 创建论坛默认组和设置信息。具体后面分析应用程序的数据模型时再来深入分析。
- Line 11-14: 如果捕获到
IntegrityError
异常,说明数据库中的相应数据已经存在,则用prompt_bool
来提示用户是否覆盖原有数据 - Line 22-24: 如何捕获到
OperationalError
异常,说明数据库不存在,用prompt_bool
提示用户是否创建数据库 - Line 33-36: 创建管理员帐户
- Line 39: 创建默认的论坛板块
我们可以通过运行下面的命令来初始化论坛数据:
python manage.py initflaskbb -u admin -p admin -e admin@kamidox.com
结束语
manage.py
主要通过Flask-Script扩展来实现开发,调试及部署过程中的数据库初始化以及一些交互调试功能,是程序必不可少的组成部分。