開篇
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 [email protected]
結束語
manage.py
主要通過Flask-Script擴展來實現開發,調試及部署過程中的數據庫初始化以及一些交互調試功能,是程序必不可少的組成部分。