FlaskBB閱讀筆記(二)

開篇

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 createallpython 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.pyinitflaskbb命令的代碼。

  • Line 1-4: 聲明瞭initflaskbb命令,並且帶三個參數,分別是usernamepasswordemail用來創建管理員用戶
  • 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擴展來實現開發,調試及部署過程中的數據庫初始化以及一些交互調試功能,是程序必不可少的組成部分。


發佈了29 篇原創文章 · 獲贊 8 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章