官术网_书友最值得收藏!

第1章 初識Flask

這一切開始于2010年4月1日,Armin Ronacher在網(wǎng)上發(fā)布了一篇關(guān)于“下一代Python微框架”的介紹文章,文章里稱這個Denied框架不依賴Python標(biāo)準(zhǔn)庫,只需要復(fù)制一份deny. py放到你的項目文件夾就可以開始編程。伴隨著一本正經(jīng)的介紹、名人推薦語、示例代碼和演示視頻,這個“虛假”的項目讓不少人都信以為真。5天后,F(xiàn)lask(http://flask.pocoo.org/)就從這么一個愚人節(jié)玩笑誕生了。

Flask是使用Python編寫的Web微框架。Web框架可以讓我們不用關(guān)心底層的請求響應(yīng)處理,更方便高效地編寫Web程序。因?yàn)镕lask核心簡單且易于擴(kuò)展,所以被稱作微框架(micro framework)。Flask有兩個主要依賴,一個是WSGI(Web Server Gateway Interface,Web服務(wù)器網(wǎng)關(guān)接口)工具集——Werkzeug(http://werkzeug.pocoo.org/),另一個是Jinja2模板引擎(http://jinja.pocoo.org/)。Flask只保留了Web開發(fā)的核心功能,其他的功能都由外部擴(kuò)展來實(shí)現(xiàn),比如數(shù)據(jù)庫集成、表單認(rèn)證、文件上傳等。如果沒有合適的擴(kuò)展,你甚至可以自己動手開發(fā)。Flask不會替你做決定,也不會限制你的選擇。總之,F(xiàn)lask可以變成任何你想要的東西,一切都由你做主。

附注

Flask(瓶子,燒瓶)的命名據(jù)說是對另一個Python Web框架——Bottle的雙關(guān)語/調(diào)侃,即另一種容器(另一個Python Web框架)。Werkzeug是德語單詞“工具(tool)”,而Jinja指日本神社,因?yàn)樯裆纾◤R)的英文temple與template(模板)相近而得名。

附注

WSGI(Web Server Gateway Interface)是Python中用來規(guī)定Web服務(wù)器如何與Python Web程序進(jìn)行溝通的標(biāo)準(zhǔn),在本書的第三部分將進(jìn)行詳細(xì)介紹。

本章將會對Flask的主要基礎(chǔ)概念進(jìn)行一些介紹,并通過一個最簡單的Flask程序來了解一些核心概念。如果你對某些概念感到疑惑,不用擔(dān)心,我們會在后面深入學(xué)習(xí)這些內(nèi)容。

在本書的第一部分,每一章都有一個對應(yīng)的示例程序,章節(jié)中的大部分示例代碼均可以在示例程序中找到。首先,請打開命令行窗口,切換到合適的目錄,然后使用下面的命令把本書的示例程序倉庫復(fù)制到本地,并切換進(jìn)項目根目錄:

        $ git clone https://github.com/greyli/helloflask.git
        $ cd helloflask

提示

如果你在Hello Flask的Git Hub頁面(https://github.com/greyli/helloflask)單擊了Fork按鈕,那么可以使用你自己的Git Hub用戶名來替換掉上面的greyli,這將復(fù)制一份派生倉庫,你可以自由地修改和提交代碼。

本章新涉及的Python包如下所示:

? Flask(1.0.2)

主頁:http://flask.pocoo.org/

源碼:http://github.com/pallets/flask

文檔:http://flask.pocoo.org/docs/

? pip(10.0.1)

主頁:https://github.com/pypa/pip

文檔:https://pip.pypa.io

? Pipenv(v2018.05.18)

主頁:https://github.com/pypa/pipenv

文檔:http://pipenv.readthedocs.io/

? Virtualenv(15.1.0)

主頁:https://github.com/pypa/virtualenv

文檔:https://virtualenv.pypa.io

? Pipfile(0.0.2)

主頁:https://github.com/pypa/pipfile

? python-dotenv(0.8.2)

主頁:https://github.com/theskumar/python-dotenv

? Watchdog(0.8.3)

主頁:https://github.com/gorakhargosh/watchdog

文檔:https://pythonhosted.org/watchdog/

1.1 搭建開發(fā)環(huán)境

在前言中,我們已經(jīng)簡單介紹了閱讀本書所需要的基礎(chǔ)知識,現(xiàn)在我們開始正式的搭建開發(fā)環(huán)境。

1.1.1 Pipenv工作流

Pipenv是基于pip的Python包管理工具,它和pip的用法非常相似,可以看作pip的加強(qiáng)版,它的出現(xiàn)解決了舊的pip+virtualenv+requirements.txt的工作方式的弊端。具體來說,它是pip、Pipfile和Virtualenv的結(jié)合體,它讓包安裝、包依賴管理和虛擬環(huán)境管理更加方便,使用它可以實(shí)現(xiàn)高效的Python項目開發(fā)工作流。如果你還不熟悉這些工具,不用擔(dān)心,我們會在下面逐一進(jìn)行介紹。

1.安裝pip和Pipenv

pip是用來安裝Python包的工具。如果你使用Python 2.7.9及以上版本或Python 3.4及以上版本,那么pip已經(jīng)安裝好了。可以使用下面的命令檢查pip是否已經(jīng)安裝:

        $ pip --version

如果報錯,那么你需要自己安裝pip。最簡單的方式是下載并使用Python執(zhí)行g(shù)et-pip.py文件(https://bootstrap.pypa.io/get-pip.py)。

下面這條命令你經(jīng)常在各種文檔中見到:

        $ pip install <某個包的名稱>

這會從Py PI(Python Package Index,Python包索引)上下載并安裝指定的包。

附注

Py PI(https://pypi.org)是一個Python包的在線倉庫,截至2018年5月,共有13萬多個包存儲在這里。后面我們會學(xué)習(xí)如何編寫自己的Flask擴(kuò)展,并把它上傳到Py PI上。到時你就可以使用上面這條命令安裝自己編寫的包。

現(xiàn)在使用pip安裝Pipenv:

        $ pip install pipenv

在Linux或mac OS系統(tǒng)中使用sudo以全局安裝:

        $ sudo pip install pipenv

附注

如果你不想全局安裝,可以添加--user選項執(zhí)行用戶安裝(即pip install--user pipenv),并手動將用戶基礎(chǔ)二進(jìn)制目錄添加到PATH環(huán)境變量中,具體可參考https://docs.pipenv.org/install/#installing-pipenv

提示

Py PI中的包名稱不區(qū)分大小寫。出于方便的考慮,后面的安裝命令都將使用小寫名稱。

可以使用下面的命令檢查Pipenv是否已經(jīng)安裝:

        $ pipenv --version
        pipenv, version 11.10.4
2.創(chuàng)建虛擬環(huán)境

在Python中,虛擬環(huán)境(virtual enviroment)就是隔離的Python解釋器環(huán)境。通過創(chuàng)建虛擬環(huán)境,你可以擁有一個獨(dú)立的Python解釋器環(huán)境。這樣做的好處是可以為每一個項目創(chuàng)建獨(dú)立的Python解釋器環(huán)境,因?yàn)椴煌捻椖砍3蕾嚥煌姹镜膸旎騊ython版本。使用虛擬環(huán)境可以保持全局Python解釋器環(huán)境的干凈,避免包和版本的混亂,并且可以方便地區(qū)分和記錄每個項目的依賴,以便在新環(huán)境下復(fù)現(xiàn)依賴環(huán)境。

虛擬環(huán)境通常使用Virtualenv來創(chuàng)建,但是為了更方便地管理虛擬環(huán)境和依賴包,我們將會使用集成了Virtualenv的Pipenv。首先確保我們當(dāng)前工作目錄在示例程序項目的根目錄,即helloflask文件夾中,然后使用pipenv install命令為當(dāng)前的項目創(chuàng)建虛擬環(huán)境:

        $ pipenv install
        Creating a virtualenv for this project…
        ...
        Virtualenv location: /path/to/virtualenv/helloflask-5Pa0Zf Zw
        ...

這會為當(dāng)前項目創(chuàng)建一個文件夾,其中包含隔離的Python解釋器環(huán)境,并且安裝pip、wheel、setuptools等基本的包。因?yàn)槭纠绦騻}庫里包含Pipfile文件,所以這個文件中列出的依賴包也會一并被安裝,下面會具體介紹。

附注

默認(rèn)情況下,Pipenv會統(tǒng)一管理所有虛擬環(huán)境。在Windows系統(tǒng)中,虛擬環(huán)境文件夾會在C:\Users\Administrator\.virtualenvs\目錄下創(chuàng)建,而Linux或mac OS會在~/.local/share/virtualenvs/目錄下創(chuàng)建。如果你想在項目目錄內(nèi)創(chuàng)建虛擬環(huán)境文件夾,可以設(shè)置環(huán)境變量PIPENV_VENV_IN_PROJECT,這時名為.venv的虛擬環(huán)境文件夾將在項目根目錄被創(chuàng)建。

虛擬環(huán)境文件夾的目錄名稱的形式為“當(dāng)前項目目錄名+一串隨機(jī)字符”,比如helloflask-5Pa0Zf Zw。

提示

你可以通過--three和--two選項來聲明虛擬環(huán)境中使用的Python版本(分別對應(yīng)Python3和Python2),或是使用--python選項指定具體的版本號。同時要確保對應(yīng)版本的Python已經(jīng)安裝在電腦中。

在單獨(dú)使用Virtualenv時,我們通常會顯式地激活虛擬環(huán)境。在Pipenv中,可以使用pipenv shell命令顯式地激活虛擬環(huán)境:

        $ pipenv shell
        Loading .env environment variables…
        Launching subshell in virtual environment. Type 'exit' to return.

提示

當(dāng)執(zhí)行pipenv shell或pipenv run命令時,Pipenv會自動從項目目錄下的.env文件中加載環(huán)境變量。

Pipenv會啟動一個激活虛擬環(huán)境的子shell,現(xiàn)在你會發(fā)現(xiàn)命令行提示符前添加了虛擬環(huán)境名“(虛擬環(huán)境名稱)$”,比如:

        (helloflask-5Pa0Zf Zw) $

這說明我們已經(jīng)成功激活了虛擬環(huán)境,現(xiàn)在你的所有命令都會在虛擬環(huán)境中執(zhí)行。當(dāng)你需要退出虛擬環(huán)境時,使用exit命令。

注意

在Windows系統(tǒng)中使用pipenv shell激活虛擬環(huán)境時,雖然激活成功,但是命令行提示符前不會顯示虛擬環(huán)境名稱。

除了顯式地激活虛擬環(huán)境,Pipenv還提供了一個pipenv run命令,這個命令允許你不顯式激活虛擬環(huán)境即可在當(dāng)前項目的虛擬環(huán)境中執(zhí)行命令,比如:

        $ pipenv run python hello.py

這會使用虛擬環(huán)境中的Python解釋器,而不是全局的Python解釋器。事實(shí)上,和顯式激活/關(guān)閉虛擬環(huán)境的傳統(tǒng)方式相比,pipenv run是更推薦的做法,因?yàn)檫@個命令可以讓你在執(zhí)行操作時不用關(guān)心自己是否激活了虛擬環(huán)境。當(dāng)然,你可以自由選擇你偏愛的用法。

注意

為了方便書寫,本書后面涉及的諸多命令會直接寫出,省略前面的虛擬環(huán)境名稱。在實(shí)際執(zhí)行時,你需要使用pipenv shell激活虛擬環(huán)境后執(zhí)行命令,或是在命令前加入pipenv run,后面不再提示。

3.管理依賴

一個程序通常會使用很多的Python包,即依賴(dependency)。而程序不僅僅會在一臺電腦上運(yùn)行,程序部署上線時需要安裝到遠(yuǎn)程服務(wù)器上,而你也許會把它分享給朋友。如果你打算開源的話,就可能會有更多的人需要在他們的電腦上運(yùn)行。為了能順利運(yùn)行程序,他們不得不記下所有依賴包,然后使用pip或Pipenv安裝,這些重復(fù)無用的工作當(dāng)然應(yīng)該避免。在以前我們通常使用pip搭配一個requirements.txt文件來記錄依賴。但requirements.txt需要手動維護(hù),在使用上不夠靈活。Pipfile的出現(xiàn)就是為了替代難于管理的requirements.txt。

在創(chuàng)建虛擬環(huán)境時,如果項目根目錄下沒有Pipfile文件,pipenv install命令還會在項目文件夾根目錄下創(chuàng)建Pipfile和Pipfile.lock文件,前者用來記錄項目依賴包列表,而后者記錄了固定版本的詳細(xì)依賴包列表。當(dāng)我們使用Pipenv安裝/刪除/更新依賴包時,Pipfile以及Pipfile. lock會自動更新。

附注

你可以使用pipenv graph命令查看當(dāng)前環(huán)境下的依賴情況,或是在虛擬環(huán)境中使用pip list命令查看依賴列表。

當(dāng)需要在一個新的環(huán)境運(yùn)行程序時,只需要執(zhí)行pipenv install命令。Pipenv就會創(chuàng)建一個新的虛擬環(huán)境,然后自動從Pipfile中讀取依賴并安裝到新創(chuàng)建的虛擬環(huán)境中。

提示

在本書撰寫時,Pipfile項目還處于活躍的開發(fā)階段,有很多東西還沒有固定,所以這里不會過多介紹,具體請訪問Pipfile主頁了解。

1.1.2 安裝Flask

下面使用pipenv install命令在我們剛剛創(chuàng)建的虛擬環(huán)境里安裝Flask:

        $ pipenv install flask
        Installing flask...
        ...
        Successfully  installed  Jinja2-2.10  Markup Safe-1.0  Werkzeug-0.14.1  click-6.7
            flask-1.0.2 itsdangerous-0.24

提示

Pipenv會自動幫我們管理虛擬環(huán)境,所以在執(zhí)行pipenv install安裝Python包時,無論是否激活虛擬環(huán)境,包都會安裝到虛擬環(huán)境中。后面我們都將使用Pipenv安裝包,這相當(dāng)于在激活虛擬環(huán)境的情況下使用pip安裝包。只有需要在全局環(huán)境下安裝/更新/刪除包,我們才會使用pip。

從上面成功安裝的輸出內(nèi)容可以看出,除了Flask包外,同時被安裝的還有5個依賴包,它們的主要介紹如表1-1所示。

表1-1 Flask的依賴包

在大部分情況下,為了方便表述,我會直接稱Flask使用這些包提供的功能為Flask提供的功能,必要時則會具體說明。這里僅僅是打個照面,后面我們會慢慢熟悉這些包。

附注

包括Flask在內(nèi),F(xiàn)lask的5個依賴包都由Pocoo團(tuán)隊(http://www.pocoo.org/)開發(fā),主要作者均為Armin Ronacher(http://lucumr.pocoo.org/),這些項目均隸屬于Pallets項目(https://www.palletsprojects.com/)。

本書使用了最新版本的Flask(1.0.2),如果你還在使用舊版本,請使用下面的命令進(jìn)行更新:

        $ pipenv update flask

另外,本書涉及的所有Python包都將使用當(dāng)前發(fā)布的最新版本,在每一章的開始我們都會列出新涉及的Python包的版本及Git Hub主頁。如果你使用舊版本,請使用pipenv update命令更新版本。

提示

如果你手動使用pip和virtualenv管理包和虛擬環(huán)境,可以使用--upgrade或-U選項(簡寫時U為大寫)來更新包版本:pip install-U <包名稱>

1.1.3 集成開發(fā)環(huán)境

如果你還沒有順手的文本編輯器,那么可以嘗試一下IDE(Integrated Development Enviroment,集成開發(fā)環(huán)境)。對于新手來說,IDE的強(qiáng)大和完善會幫助你高效開發(fā)Flask程序,等到你熟悉了整個開發(fā)流程,可以換用更加輕量的編輯器以避免過度依賴IDE。下面我們將介紹使用Py Charm開發(fā)Flask程序的主要準(zhǔn)備步驟。

步驟1 下載并安裝Py Charm

打開Py Charm的下載頁面(http://jetbrains.com/pycharm/download/),單擊你使用的操作系統(tǒng)選項卡,然后單擊下載按鈕。你可以選擇試用專業(yè)版(Professional Edition),或是選擇免費(fèi)的社區(qū)版(Community Edition),如圖1-1所示。

圖1-1 下載Py Charm

附注

專業(yè)版有一個月的免費(fèi)試用時間。如果你是學(xué)生,可以申請專業(yè)版的免費(fèi)授權(quán)(https://www.jetbrains.com/student/)。專業(yè)版提供了更多針對Flask開發(fā)的功能,比如創(chuàng)建Flask項目模板,Jinja2語法高亮,與Flask命令行功能集成等。

Py Charm的安裝過程比較簡單,這里不再詳細(xì)說明,具體可以參考https://www.jetbrains.com/help/pycharm/requirements-installation-and-launching.html

步驟2 創(chuàng)建項目

安裝成功后,初始界面提供了多種方式創(chuàng)建新項目。這里可以單擊“Open”,選擇我們的helloflask文件夾。打開項目后的界面如圖1-2所示,左邊是項目目錄樹,右邊是代碼編輯區(qū)域。單擊左下角的方形圖標(biāo)可以隱藏和顯示工具欄,顯示工具欄后,可以看到常用的Python交互控制臺(Python Console)和終端(Terminal,即命令行工具)。

圖1-2 Py Charm主界面

步驟3 設(shè)置Python解釋器

因?yàn)镻y Charm目前還沒有添加Pipenv集成支持(最新進(jìn)展可訪問https://youtrack.jetbrains.com/issue/PY-26492查看),我們需要手動使用pipenv命令安裝依賴,同時還需要為項目設(shè)置正確的Python解釋器。單擊菜單欄中的File→Settings打開設(shè)置,然后單擊Project: helloflask-Project Interpreter選項打開項目Python解釋器設(shè)置窗口,如圖1-3所示。

圖1-3 設(shè)置項目Python解釋器

單擊選擇字段右側(cè)的設(shè)置圖標(biāo),然后單擊“Add Local Python Interpreter”,在彈出的窗口選擇Virtualenv Enviroment→Existing enviroment,在下拉框或是自定義窗口找到我們之前創(chuàng)建的虛擬環(huán)境中的Python解釋器路徑,如圖1-4所示。

圖1-4 選擇虛擬環(huán)境中的Python解釋器

使用pipenv--venv命令可以查看項目對應(yīng)的虛擬環(huán)境路徑。Linux或mac OS系統(tǒng)下的路徑類似~/.local/share/virtualenvs/helloflask-k SN7ec1K/bin/python或~/.virtualenvs/helloflask-k SN7ec1K/bin/python,Windows系統(tǒng)的路徑類似C:\Users\Administrator\.virtualenvs\helloflask-5Pa0Zf Zw\Scripts\python.exe。

正確設(shè)置以后,重新創(chuàng)建一個Terminal會話,你會發(fā)現(xiàn)命令行提示符前出現(xiàn)了虛擬環(huán)境名稱,說明虛擬環(huán)境已經(jīng)激活。以后每次打開項目,Py Charm都會自動幫你激活虛擬環(huán)境,并且把工作目錄定位到項目根目錄。具體行為你也可以在Settings→Tools→Terminal中設(shè)置。

附注

你可以通過Py Charm提供的入門教程(https://www.jetbrains.com/pycharm/documentation/)來了解Py Charm的更多用法。

最后,我們的Web程序需要在Web瀏覽器中訪問,所以你還需要安裝一個Web瀏覽器,推薦使用Firefox(https://www.mozilla.org/firefox/)或Chrome(https://www.google.com/chrome/)。現(xiàn)在你已經(jīng)做好了一切準(zhǔn)備,F(xiàn)lask之旅正式啟程了!下面我們會通過一個最小的Flask程序來了解Flask的基本運(yùn)作方式。

1.2 Hello, Flask!

本書的第一部分每一章對應(yīng)一個示例程序,分別存儲在demos目錄下的不同文件夾中。本章的示例程序在helloflask/demos/hello目錄下,使用下面的命令切換到該目錄:

        $ cd demos/hello

在hello目錄下的app.py腳本中包含一個最小的Flask程序,如代碼清單1-1所示。

代碼清單1-1 hello/app.py:最小的Flask程序

        from flask import Flask
        app = Flask(__name__)
        @app.route('/')
        def index():
            return '<h1>Hello Flask!</h1>'

你也許已經(jīng)猜到它能做什么了,下面讓我們先來一步步分解這個程序。

提示

對于簡單的程序來說,程序的主模塊一般命令為app.py。你也可以使用其他名稱,比如hello.py,但是要避免使用flask.py,因?yàn)檫@和Flask本身沖突。

1.2.1 創(chuàng)建程序?qū)嵗?/h4>

我們安裝Flask時,它會在Python解釋器中創(chuàng)建一個flask包,我們可以通過flask包的構(gòu)造文件導(dǎo)入所有開放的類和函數(shù)。我們先從flask包導(dǎo)入Flask類,這個類表示一個Flask程序。實(shí)例化這個類,就得到我們的程序?qū)嵗齛pp:

        from flask import Flask
        app = Flask(__name__)

傳入Flask類構(gòu)造方法的第一個參數(shù)是模塊或包的名稱,我們應(yīng)該使用特殊變量__name__。Python會根據(jù)所處的模塊來賦予__name__變量相應(yīng)的值,對于我們的程序來說(app.py),這個值為app。除此之外,這也會幫助Flask在相應(yīng)的文件夾里找到需要的資源,比如模板和靜態(tài)文件。

提示

Flask類是Flask的核心類,它提供了很多與程序相關(guān)的屬性和方法。在后面,我們經(jīng)常會直接在程序?qū)嵗齛pp上調(diào)用這些屬性和方法來實(shí)現(xiàn)相關(guān)功能。在第一次提及Flask類中的某個方法或?qū)傩詴r,我們會直接以實(shí)例方法/屬性的形式寫出,比如存儲程序名稱的屬性為app.name。

1.2.2 注冊路由

在一個Web應(yīng)用里,客戶端和服務(wù)器上的Flask程序的交互可以簡單概括為以下幾步:

1)用戶在瀏覽器輸入URL訪問某個資源。

2)Flask接收用戶請求并分析請求的URL。

3)為這個URL找到對應(yīng)的處理函數(shù)。

4)執(zhí)行函數(shù)并生成響應(yīng),返回給瀏覽器。

5)瀏覽器接收并解析響應(yīng),將信息顯示在頁面中。

在上面這些步驟中,大部分都由Flask完成,我們要做的只是建立處理請求的函數(shù),并為其定義對應(yīng)的URL規(guī)則。只需為函數(shù)附加app.route()裝飾器,并傳入URL規(guī)則作為參數(shù),我們就可以讓URL與函數(shù)建立關(guān)聯(lián)。這個過程我們稱為注冊路由(route),路由負(fù)責(zé)管理URL和函數(shù)之間的映射,而這個函數(shù)則被稱為視圖函數(shù)(view function)。

附注

路由的含義可以從字面意義理解,作為動詞時,它的含義是“按某路線發(fā)送”,即調(diào)用與請求URL對應(yīng)的視圖函數(shù)。

在這個程序里,app.route()裝飾器把根地址/和index()函數(shù)綁定起來,當(dāng)用戶訪問這個URL時就會觸發(fā)index()函數(shù)。這個視圖函數(shù)可以像其他普通函數(shù)一樣執(zhí)行任意操作,比如從數(shù)據(jù)庫中獲取信息,獲取請求信息,對用戶輸入的數(shù)據(jù)進(jìn)行計算和處理等。最后,視圖函數(shù)返回的值將作為響應(yīng)的主體,一般來說,響應(yīng)的主體就是呈現(xiàn)在瀏覽器窗口的HTML頁面。在最小程序中,視圖函數(shù)index()返回一行問候:

        @app.route('/')
        def index():
            return '<h1>Hello, World!</h1>'

雖然這個程序相當(dāng)簡單,但它卻是大部分Flask程序的基本模式。在復(fù)雜的程序中,我們會有許多個視圖函數(shù)分別處理不同URL的請求,在視圖函數(shù)中會完成更多的工作,并且返回包含各種鏈接、表單、圖片的HTML文件,而不僅僅是一行字符串。返回的頁面中的鏈接又會指向其他URL,被單擊后觸發(fā)對應(yīng)的視圖函數(shù),獲得不同的返回值,從而顯示不同的頁面,這就是我們?yōu)g覽網(wǎng)頁時的體驗(yàn)。

提示

route()裝飾器的第一個參數(shù)是URL規(guī)則,用字符串表示,必須以斜杠(/)開始。這里的URL是相對URL(又稱為內(nèi)部URL),即不包含域名的URL。以域名www.helloflask.com為例,“/”對應(yīng)的是根地址(即www.helloflask.com),如果把URL規(guī)則改為“/hello”,則實(shí)際的絕對地址(外部地址)是www.helloflask.com/hello

假如這個程序部署在域名為www.helloflask.com的服務(wù)器上,當(dāng)啟動服務(wù)器后,只要你在瀏覽器里訪問www.helloflask.com,就會看到瀏覽器上顯示一行“Hello,F(xiàn)lask!”問候。

附注

URL(Uniform Resource Lacator,統(tǒng)一資源定位符)正是我們使用瀏覽器訪問網(wǎng)頁時輸入的網(wǎng)址,比如http://helloflask.com/。簡單來說,URL就是指向網(wǎng)絡(luò)中某個資源的地址。

1.為視圖綁定多個URL

一個視圖函數(shù)可以綁定多個URL,比如下面的代碼把/hi和/hello都綁定到say_hello()函數(shù)上,這就會為say_hello視圖注冊兩個路由,用戶訪問這兩個URL均會觸發(fā)say_hello()函數(shù),獲得相同的響應(yīng),如代碼清單1-2所示。

代碼清單1-2 hello/app.py:綁定多個URL到同一視圖函數(shù)

        @app.route('/hi')
        @app.route('/hello')
        def say_hello():
            return '<h1>Hello, Flask!</h1>'
2.動態(tài)URL

我們不僅可以為視圖函數(shù)綁定多個URL,還可以在URL規(guī)則中添加變量部分,使用“<變量名>”的形式表示。Flask處理請求時會把變量傳入視圖函數(shù),所以我們可以添加參數(shù)獲取這個變量值。代碼清單1-3中的視圖函數(shù)greet(),它的URL規(guī)則包含一個name變量。

代碼清單1-3 hello/app.py:添加URL變量

        @app.route('/greet/<name>')
        def greet(name):
            return '<h1>Hello, %s!</h1>' % name

因?yàn)閁RL中可以包含變量,所以我們將傳入app.route()的字符串稱為URL規(guī)則,而不是URL。Flask會解析請求并把請求的URL與視圖函數(shù)的URL規(guī)則進(jìn)行匹配。比如,這個greet視圖的URL規(guī)則為/greet/<name>,那么類似/greet/foo、/greet/bar的請求都會觸發(fā)這個視圖函數(shù)。

附注

順便說一句,雖然示例中的URL規(guī)則和視圖函數(shù)名稱都包含相同的部分(greet),但這并不是必須的,你可以自由修改URL規(guī)則和視圖函數(shù)名稱。

這個視圖返回的響應(yīng)會隨著請求URL中的name變量而變化。假設(shè)程序運(yùn)行在http://helloflask.com上,當(dāng)我們在瀏覽器里訪問http://helloflask.com/hello/Grey時,可以看到瀏覽器上顯示“Hello,Grey!”。

當(dāng)URL規(guī)則中包含變量時,如果用戶訪問的URL中沒有添加變量,比如/greet,那么Flask在匹配失敗后會返回一個404錯誤響應(yīng)。一個很常見的行為是在app.route()裝飾器里使用defaults參數(shù)設(shè)置URL變量的默認(rèn)值,這個參數(shù)接收字典作為輸入,存儲URL變量和默認(rèn)值的映射。在下面的代碼中,我們?yōu)間reet視圖新添加了一個app.route()裝飾器,為/greet設(shè)置了默認(rèn)的name值:

        @app.route('/greet', defaults={'name': 'Programmer'})
        @app.route('/greet/<name>')
        def greet(name):
            return '<h1>Hello, %s!</h1>' % name

這時如果用戶訪問/greet,那么變量name會使用默認(rèn)值Programmer,視圖函數(shù)返回<h1>Hello,Programmer! </h1>。上面的用法實(shí)際效果等同于:

        @app.route('/greet')
        @app.route('/greet/<name>')
        def greet(name='Programmer'):
            return '<h1>Hello, %s!</h1>' % name

1.3 啟動開發(fā)服務(wù)器

Flask內(nèi)置了一個簡單的開發(fā)服務(wù)器(由依賴包Werkzeug提供),足夠在開發(fā)和測試階段使用。

注意

在生產(chǎn)環(huán)境需要使用性能夠好的生產(chǎn)服務(wù)器,以提升安全和性能,具體在本書第三部分會進(jìn)行介紹。

1.3.1 Run,F(xiàn)lask,Run!

Flask通過依賴包Click內(nèi)置了一個CLI(Command Line Interface,命令行交互界面)系統(tǒng)。當(dāng)我們安裝Flask后,會自動添加一個flask命令腳本,我們可以通過flask命令執(zhí)行內(nèi)置命令、擴(kuò)展提供的命令或是我們自己定義的命令。其中,flask run命令用來啟動內(nèi)置的開發(fā)服務(wù)器:

        $ flask run
          * Environment: production
            WARNING: Do not use the development server in a production environment.
            Use a production WSGI server instead.
          * Debug mode: off
              * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

注意

確保執(zhí)行命令前激活了虛擬環(huán)境(pipenv shell),否則需要使用pipenv run flask run命令啟動開發(fā)服務(wù)器。后面將不再提示。

你可以執(zhí)行flask--help查看所有可用的命令。

提示

如果執(zhí)行flask run命令后顯示命令未找到提示(command not found)或其他錯誤,可以嘗試使用python-m flask run啟動服務(wù)器,其他命令亦同。

flask run命令運(yùn)行的開發(fā)服務(wù)器默認(rèn)會監(jiān)聽http://127.0.0.1:5000/地址(按Crtl+C退出),并開啟多線程支持。當(dāng)我們打開瀏覽器訪問這個地址時,會看到網(wǎng)頁上顯示“Hello,World!”,如圖1-5所示。

圖1-5 “Hello,World!”程序主頁

提示

http://127.0.0.1即localhost,是指向本地機(jī)的IP地址,一般用來測試。Flask默認(rèn)使用5000端口,對于上面的地址,你也可以使用http://localhost:5000/。在本書中這兩者會交替使用,除了地址不同外,兩者沒有實(shí)際區(qū)別,即域名和IP地址的映射關(guān)系。

提示

舊的啟動開發(fā)服務(wù)器的方式是使用app.run()方法,目前已不推薦使用(deprecated)。

1.自動發(fā)現(xiàn)程序?qū)嵗?/h5>

一般來說,在執(zhí)行flask run命令運(yùn)行程序前,我們需要提供程序?qū)嵗谀K的位置。我們在上面可以直接運(yùn)行程序,是因?yàn)镕lask會自動探測程序?qū)嵗詣犹綔y存在下面這些規(guī)則:

? 從當(dāng)前目錄尋找app.py和wsgi.py模塊,并從中尋找名為app或application的程序?qū)嵗?/p>

? 從環(huán)境變量FLASK_APP對應(yīng)的值尋找名為app或application的程序?qū)嵗?/p>

因?yàn)槲覀兊某绦蛑髂K命名為app.py,所以flask run命令會自動在其中尋找程序?qū)嵗H绻愕某绦蛑髂K是其他名稱,比如hello.py,那么需要設(shè)置環(huán)境變量FLASK_APP,將包含程序?qū)嵗哪K名賦值給這個變量。Linux或mac OS系統(tǒng)使用export命令:

        $ export FLASK_APP=hello

在Windows系統(tǒng)中使用set命令:

        > set FLASK_APP=hello
2.管理環(huán)境變量

Flask的自動發(fā)現(xiàn)程序?qū)嵗龣C(jī)制還有第三條規(guī)則:如果安裝了python-dotenv,那么在使用flask run或其他命令時會使用它自動從.flaskenv文件和.env文件中加載環(huán)境變量。

附注

當(dāng)安裝了python-dotenv時,F(xiàn)lask在加載環(huán)境變量的優(yōu)先級是:手動設(shè)置的環(huán)境變量>.env中設(shè)置的環(huán)境變量>.flaskenv設(shè)置的環(huán)境變量。

除了FLASK_APP,在后面我們還會用到其他環(huán)境變量。環(huán)境變量在新創(chuàng)建命令行窗口或重啟電腦后就清除了,每次都要重設(shè)變量有些麻煩。而且如果你同時開發(fā)多個Flask程序,這個FLASK_APP就需要在不同的值之間切換。為了避免頻繁設(shè)置環(huán)境變量,我們可以使用python-dotenv管理項目的環(huán)境變量,首先使用Pipenv將它安裝到虛擬環(huán)境:

        $ pipenv install python-dotenv

我們在項目根目錄下分別創(chuàng)建兩個文件:.env和.flaskenv。.flaskenv用來存儲和Flask相關(guān)的公開環(huán)境變量,比如FLASK_APP;而.env用來存儲包含敏感信息的環(huán)境變量,比如后面我們會用來配置Email服務(wù)器的賬戶名與密碼。在.flaskenv或.env文件中,環(huán)境變量使用鍵值對的形式定義,每行一個,以#開頭的為注釋,如下所示:

        SOME_VAR=1
        # 這是注釋
        FOO="BAR"

注意

.env包含敏感信息,除非是私有項目,否則絕對不能提交到Git倉庫中。當(dāng)你開發(fā)一個新項目時,記得把它的名稱添加到.gitignore文件中,這會告訴Git忽略這個文件。gitignore文件是一個名為.gitignore的文本文件,它存儲了項目中Git提交時的忽略文件規(guī)則清單。Python項目的.gitignore模板可以參考https://github.com/github/gitignore/blob/master/Python.gitignore。使用Py Charm編寫程序時會產(chǎn)生一些配置文件,這些文件保存在項目根目錄下的.idea目錄下,關(guān)于這些文件的忽略設(shè)置可以參考https://www.gitignore.io/api/pycharm

3.使用Py Charm運(yùn)行服務(wù)器

在Py Charm中,雖然我們可以使用內(nèi)置的命令行窗口執(zhí)行命令以啟動開發(fā)服務(wù)器,但是在開發(fā)時使用Py Charm內(nèi)置的運(yùn)行功能更加方便。在2018.1版本后的專業(yè)版添加了Flask命令行支持,在舊版本或社區(qū)版中,如果要使用Py Charm運(yùn)行程序,還需要進(jìn)行一些設(shè)置。

首先,在Py Charm中,單擊菜單欄中的Run→Edit Configurations打開運(yùn)行配置窗口。圖1-6中標(biāo)出了在Py Charm中設(shè)置一個運(yùn)行配置的具體步驟序號。

圖1-6 運(yùn)行Flask程序的配置

打開新建配置窗口后,具體的步驟如下所示:

步驟1 單擊左側(cè)的“+”符號打開下拉列表。

步驟2 新建一個Python類型的運(yùn)行配置(如果你使用的是專業(yè)版,則可以直接選擇Flask server),并在右側(cè)的Name字段輸入一個合適的名稱,比如“Run hello”。

步驟3 勾選“Single instance only”。

步驟4 將第一項配置字段通過下列選項選為“Module Name”。

步驟5 填入模塊名稱flask。

步驟6 第二欄的“Parameters”填入要執(zhí)行的命令run,你也可以附加其他啟動選項。

步驟7 在“Working directory”字段中選擇程序所在的目錄作為工作目錄。

提示

我們可以單擊左上方的復(fù)制圖標(biāo)復(fù)制一份配置,然后稍加修改就可以用于其他flask命令,包括擴(kuò)展提供的命令,或是我們自定義的命令。

現(xiàn)在單擊Apply或OK保存并關(guān)閉窗口。在Py Charm右上方選擇我們創(chuàng)建的運(yùn)行配置,然后單擊綠色三角形的運(yùn)行按鈕即可啟動開發(fā)服務(wù)器。

注意

因?yàn)楸菊率纠绦虻哪K名稱為app.py,F(xiàn)lask會自動從中尋找程序?qū)嵗晕覀冊赑y Charm中的運(yùn)行設(shè)置可以正確啟動程序。如果你不打算使用python-dotenv來管理環(huán)境變量,那么需要修改Py Charm的運(yùn)行配置:在Enviroment variable字段中添加環(huán)境變量FLASK_APP并設(shè)置正確的值。

1.3.2 更多的啟動選項

1.使服務(wù)器外部可見

我們在上面啟動的Web服務(wù)器默認(rèn)是對外不可見的,可以在run命令后添加--host選項將主機(jī)地址設(shè)為0.0.0.0使其對外可見:

        $ flask run --host=0.0.0.0

這會讓服務(wù)器監(jiān)聽所有外部請求。個人計算機(jī)(主機(jī))一般沒有公網(wǎng)IP(公有地址),所以你的程序只能被局域網(wǎng)內(nèi)的其他用戶通過你的個人計算機(jī)的內(nèi)網(wǎng)IP(私有地址)訪問,比如你的內(nèi)網(wǎng)IP為192.168.191.1。當(dāng)局域網(wǎng)內(nèi)的其他用戶訪問http://192.168.191.1:5000時,也會看到瀏覽器里顯示一行“Hello,F(xiàn)lask!”。

提示

把程序安裝在擁有公網(wǎng)IP的服務(wù)器上,讓互聯(lián)網(wǎng)上的所有人都可以訪問是我們最后要介紹的程序部署部分的內(nèi)容。如果你迫切地想把你的程序分享給朋友們,可以考慮使用ngrok(https://ngrok.com/)、Localtunnel(https://localtunnel.github.io/www/)等內(nèi)網(wǎng)穿透/端口轉(zhuǎn)發(fā)工具。

2.改變默認(rèn)端口

Flask提供的Web服務(wù)器默認(rèn)監(jiān)聽5000端口,你可以在啟動時傳入?yún)?shù)來改變它:

        $ flask run --port=8000

這時服務(wù)器會監(jiān)聽來自8000端口的請求,程序的主頁地址也相應(yīng)變成了http://localhost:8000/

附注

執(zhí)行flask run命令時的host和port選項也可以通過環(huán)境變量FLASK_RUN_HOST和FLASK_RUN_PORT設(shè)置。事實(shí)上,F(xiàn)lask內(nèi)置的命令都可以使用這種模式定義默認(rèn)選項值,即“FLASK_<COMMAND>_<OPTION>”,你可以使用flask--help命令查看所有可用的命令。

1.3.3 設(shè)置運(yùn)行環(huán)境

開發(fā)環(huán)境(development enviroment)和生產(chǎn)環(huán)境(production enviroment)是我們后面會頻繁接觸到的概念。開發(fā)環(huán)境是指我們在本地編寫和測試程序時的計算機(jī)環(huán)境,而生產(chǎn)環(huán)境與開發(fā)環(huán)境相對,它指的是網(wǎng)站部署上線供用戶訪問時的服務(wù)器環(huán)境。

根據(jù)運(yùn)行環(huán)境的不同,F(xiàn)lask程序、擴(kuò)展以及其他程序會改變相應(yīng)的行為和設(shè)置。為了區(qū)分程序運(yùn)行環(huán)境,F(xiàn)lask提供了一個FLASK_ENV環(huán)境變量用來設(shè)置環(huán)境,默認(rèn)為production(生產(chǎn))。在開發(fā)時,我們可以將其設(shè)為development(開發(fā)),這會開啟所有支持開發(fā)的特性。為了方便管理,我們將把環(huán)境變量FLASK_ENV的值寫入.flaskenv文件中:

        FLASK_ENV=development

現(xiàn)在啟動程序,你會看到下面的輸出提示:

        $ flask run
          * Environment: development
          * Debug mode: on
          * Debugger is active!
          * Debugger PIN: 202-005-064
          * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

在開發(fā)環(huán)境下,調(diào)試模式(Debug Mode)將被開啟,這時執(zhí)行flask run啟動程序會自動激活Werkzeug內(nèi)置的調(diào)試器(debugger)和重載器(reloader),它們會為開發(fā)帶來很大的幫助。

提示

如果你想單獨(dú)控制調(diào)試模式的開關(guān),可以通過FLASK_DEBUG環(huán)境變量設(shè)置,設(shè)為1則開啟,設(shè)為0則關(guān)閉,不過通常不推薦手動設(shè)置這個值。

注意

在生產(chǎn)環(huán)境中部署程序時,絕不能開啟調(diào)試模式。盡管PIN碼可以避免用戶任意執(zhí)行代碼,提高攻擊者利用調(diào)試器的難度,但并不能確保調(diào)試器完全安全,會帶來巨大的安全隱患。而且攻擊者可能會通過調(diào)試信息獲取你的數(shù)據(jù)庫結(jié)構(gòu)等容易帶來安全問題的信息。另一方面,調(diào)試界面顯示的錯誤信息也會讓普通用戶感到困惑。

1.調(diào)試器

Werkzeug提供的調(diào)試器非常強(qiáng)大,當(dāng)程序出錯時,我們可以在網(wǎng)頁上看到詳細(xì)的錯誤追蹤信息,這在調(diào)試錯誤時非常有用。運(yùn)行中的調(diào)試器如圖1-7所示。

圖1-7 調(diào)試器界面

調(diào)試器允許你在錯誤頁面上執(zhí)行Python代碼。單擊錯誤信息右側(cè)的命令行圖標(biāo),會彈出窗口要求輸入PIN碼,也就是在啟動服務(wù)器時命令行窗口打印出的調(diào)試器PIN碼(Debugger PIN)。輸入PIN碼后,我們可以單擊錯誤堆棧的某個節(jié)點(diǎn)右側(cè)的命令行界面圖標(biāo),這會打開一個包含代碼執(zhí)行上下文信息的Python Shell,我們可以利用它來進(jìn)行調(diào)試。

2.重載器

當(dāng)我們對代碼做了修改后,期望的行為是這些改動立刻作用到程序上。重載器的作用就是監(jiān)測文件變動,然后重新啟動開發(fā)服務(wù)器。當(dāng)我們修改了腳本內(nèi)容并保存后,會在命令行看到下面的輸出:

        Detected change in '/path/to/app.py', reloading
          * Restarting with stat

默認(rèn)會使用Werkzeug內(nèi)置的stat重載器,它的缺點(diǎn)是耗電較嚴(yán)重,而且準(zhǔn)確性一般。為了獲得更優(yōu)秀的體驗(yàn),我們可以安裝另一個用于監(jiān)測文件變動的Python庫Watchdog,安裝后Werkzeug會自動使用它來監(jiān)測文件變動:

        $ pipenv install watchdog --dev

因?yàn)檫@個包只在開發(fā)時才會用到,所以我們在安裝命令后添加了一個--dev選項,這用來把這個包聲明為開發(fā)依賴。在Pipfile文件中,這個包會被添加到dev-packages部分。

不過,如果項目中使用了單獨(dú)的CSS或Java Script文件時,那么瀏覽器可能會緩存這些文件,從而導(dǎo)致對文件做出的修改不能立刻生效。在瀏覽器中,我們可以按下Crtl+F5或Shift+F5執(zhí)行硬重載(hard reload),即忽略緩存并重載(刷新)頁面。

提示

當(dāng)在一個新電腦創(chuàng)建運(yùn)行環(huán)境時,使用pipenv install命令時需要添加額外的--dev選項才會安裝dev-packages部分定義的開發(fā)依賴包。

1.4 Python Shell

本書有許多操作需要在Python Shell(即Python交互式解釋器)里執(zhí)行。在開發(fā)Flask程序時,我們并不會直接使用python命令啟動Python Shell,而是使用flask shell命令:

        $ flask shell
        App: app [development]
        Instance: Path/to/your/helloflask/instance
        >>>

注意

和其他flask命令相同,執(zhí)行這個命令前我們要確保程序?qū)嵗梢员徽U业健?/p>

在本書中,如果代碼片段前的提示符為三個大于號,即“>>>”,那么就表示這些代碼需要在使用flask shell命令打開的Python Shell中執(zhí)行。

提示

Python Shell可以執(zhí)行exit()或quit()退出,在Windows系統(tǒng)上可以使用Crtl+Z并按Enter退出;在Linux和mac OS則可以使用Crtl+D退出。

使用flask shell命令打開的Python Shell自動包含程序上下文,并且已經(jīng)導(dǎo)入了app實(shí)例:

        >>> app
        <Flask 'app'>
        >>> app.name
          'app'

附注

上下文(context)可以理解為環(huán)境。為了正常運(yùn)行程序,一些操作相關(guān)的狀態(tài)和數(shù)據(jù)需要被臨時保存下來,這些狀態(tài)和數(shù)據(jù)被統(tǒng)稱為上下文。在Flask中,上下文有兩種,分別為程序上下文和請求上下文,后面我們會詳細(xì)了解。

1.5 Flask擴(kuò)展

在本書中我們將會接觸到很多Flask擴(kuò)展。擴(kuò)展(extension)即使用Flask提供的API接口編寫的Python庫,可以為Flask程序添加各種各樣的功能。大部分Flask擴(kuò)展用來集成其他庫,作為Flask和其他庫之間的薄薄一層膠水。因?yàn)镕lask擴(kuò)展的編寫有一些約定,所以初始化的過程大致相似。大部分?jǐn)U展都會提供一個擴(kuò)展類,實(shí)例化這個類,并傳入我們創(chuàng)建的程序?qū)嵗齛pp作為參數(shù),即可完成初始化過程。通常,擴(kuò)展會在傳入的程序?qū)嵗献砸恍┨幚砗瘮?shù),并加載一些配置。

以某擴(kuò)展實(shí)現(xiàn)了Foo功能為例,這個擴(kuò)展的名稱將是Flask-Foo或Foo-Flask;程序包或模塊的命名使用小寫加下劃線,即flask_foo(即導(dǎo)入時的名稱);用于初始化的類一般為Foo,實(shí)例化的類實(shí)例一般使用小寫,即foo。初始化這個假想中的Flask-Foo擴(kuò)展的示例如下所示:

        from flask import Flask
        from flask_foo import Foo
        app = Flask(__name__)
        foo = Foo(app)

在日常開發(fā)中,大多數(shù)情況下,我們沒有必要重復(fù)制造輪子,所以選用擴(kuò)展可以避免讓項目變得臃腫和復(fù)雜。盡管使用擴(kuò)展可以簡化操作,快速集成某個功能,但同時也會降低靈活性。如果過度使用擴(kuò)展,在不需要的地方引入,那么相應(yīng)也會導(dǎo)致代碼不容易維護(hù)。更糟糕的是,質(zhì)量差的擴(kuò)展可能還會帶來潛在的Bug,而不同擴(kuò)展之間也可能會出現(xiàn)沖突。因此,在編寫程序時,應(yīng)該盡量從實(shí)際需求出發(fā),只在需要的時候使用擴(kuò)展,并把擴(kuò)展的質(zhì)量和兼容性作為考慮因素,盡量在效率和靈活性之間達(dá)到平衡。

附注

早期版本的Flask擴(kuò)展使用flaskext.foo或flask.ext.something的形式導(dǎo)入,在實(shí)際使用中帶來了許多問題,因此Flask官方推薦以flask_something形式導(dǎo)入擴(kuò)展。在1.0版本以后的Flask中,舊的擴(kuò)展導(dǎo)入方式已被移除。

1.6 項目配置

在很多情況下,你需要設(shè)置程序的某些行為,這時你就需要使用配置變量。在Flask中,配置變量就是一些大寫形式的Python變量,你也可以稱之為配置參數(shù)或配置鍵。使用統(tǒng)一的配置變量可以避免在程序中以硬編碼(hard coded)的形式設(shè)置程序。

在一個項目中,你會用到許多配置:Flask提供的配置,擴(kuò)展提供的配置,還有程序特定的配置。和平時使用變量不同,這些配置變量都通過Flask對象的app.config屬性作為統(tǒng)一的接口來設(shè)置和獲取,它指向的Config類實(shí)際上是字典的子類,所以你可以像操作其他字典一樣操作它。

附注

Flask內(nèi)置的配置可以訪問Flask文檔的配置章節(jié)(flask.pocoo.org/docs/latest/config/)查看,擴(kuò)展提供的配置也可以在對應(yīng)的文檔中查看。

Flask提供了很多種方式來加載配置。比如,你可以像在字典中添加一個鍵值對一樣來設(shè)置一個配置:

        app.config['ADMIN_NAME'] = 'Peter'

注意

配置的名稱必須是全大寫形式,小寫的變量將不會被讀取。

使用update()方法則可以一次加載多個值:

        app.config.update(
            TESTING=True,
            SECRET_KEY='_5#y F4Q8z\n\xec]/'
        )

除此之外,你還可以把配置變量存儲在單獨(dú)的Python腳本、JSON格式的文件或是Python類中,config對象提供了相應(yīng)的方法來導(dǎo)入配置,具體我們會在后面了解。

和操作字典一樣,讀取一個配置就是從config字典里通過將配置變量的名稱作為鍵讀取對應(yīng)的值:

        value = app.config['ADMIN_NAME']

提示

某些擴(kuò)展需要讀取配置值來完成初始化操作,比如Flask-Mail,因此我們應(yīng)該盡量將加載配置的操作提前,最好在程序?qū)嵗齛pp創(chuàng)建后就加載配置。

1.7 URL與端點(diǎn)

在Web程序中,URL無處不在。如果程序中的URL都是以硬編碼的方式寫出,那么將會大大降低代碼的易用性。比如,當(dāng)你修改了某個路由的URL規(guī)則,那么程序里對應(yīng)的URL都要一個一個進(jìn)行修改。更好的解決辦法是使用Flask提供的url_for()函數(shù)獲取URL,當(dāng)路由中定義的URL規(guī)則被修改時,這個函數(shù)總會返回正確的URL。

調(diào)用url_for()函數(shù)時,第一個參數(shù)為端點(diǎn)(endpoint)值。在Flask中,端點(diǎn)用來標(biāo)記一個視圖函數(shù)以及對應(yīng)的URL規(guī)則。端點(diǎn)的默認(rèn)值為視圖函數(shù)的名稱,至于為什么不直接使用視圖函數(shù)名,而要引入端點(diǎn)這個概念,我們會在后面了解。

比如,下面的視圖函數(shù):

        @app.route('/')
        def index():
            return 'Hello Flask!'

這個路由的端點(diǎn)即視圖函數(shù)的名稱index,調(diào)用url_for('index')即可獲取對應(yīng)的URL,即“/”。

提示

在app.route()裝飾器中使用endpoint參數(shù)可以自定義端點(diǎn)值,不過我們通常不需要這樣做。

如果URL含有動態(tài)部分,那么我們需要在url_for()函數(shù)里傳入相應(yīng)的參數(shù),以下面的視圖函數(shù)為例:

        @app.route('/hello/<name>')
        def greet(name):
            return 'Hello %s!' % name

這時使用url_for('say_hello',name='Jack')得到的URL為“/hello/Jack”。

提示

我們使用url_for()函數(shù)生成的URL是相對URL(即內(nèi)部URL),即URL中的path部分,比如“/hello”,不包含根URL。相對URL只能在程序內(nèi)部使用。如果你想要生成供外部使用的絕對URL,可以在使用url_for()函數(shù)時,將_external參數(shù)設(shè)為True,這會生成完整的URL,比如http://helloflask.com/hello,在本地運(yùn)行程序時則會獲得http://localhost:5000/hello

1.8 Flask命令

除了Flask內(nèi)置的flask run等命令,我們也可以自定義命令。在虛擬環(huán)境安裝Flask后,包含許多內(nèi)置命令的flask腳本就可以使用了。在前面我們已經(jīng)接觸了很多flask命令,比如運(yùn)行服務(wù)器的flask run,啟動shell的flask shell。

通過創(chuàng)建任意一個函數(shù),并為其添加app.cli.command()裝飾器,我們就可以注冊一個flask命令。代碼清單1-4創(chuàng)建了一個自定義的hello()命令函數(shù),在函數(shù)中我們?nèi)匀恢皇谴蛴∫恍袉柡颉?/p>

代碼清單1-4 hello/app.py:創(chuàng)建自定義命令

        @app.cli.command()
        def hello():
            click.echo('Hello, Human!')

函數(shù)的名稱即為命令名稱,這里注冊的命令即hello,你可以使用flask hello命令來觸發(fā)函數(shù)。作為替代,你也可以在app.cli.command()裝飾器中傳入?yún)?shù)來設(shè)置命令名稱,比如app.cli.command('say-hello')會把命令名稱設(shè)置為say-hello,完整的命令即flask say-hello。

借助click模塊的echo()函數(shù),我們可以在命令行界面輸出字符。命令函數(shù)的文檔字符串則會作為幫助信息顯示(flask hello--help)。在命令行下執(zhí)行flask hello命令就會觸發(fā)這個hello()函數(shù):

        $ flask hello
        Hello, Human!

在命令下執(zhí)行flask--help可以查看Flask提供的命令幫助文檔,我們自定義的hello命令也會出現(xiàn)在輸出的命令列表中,如下所示:

        $ flask --help
        Usage: flask [OPTIONS] COMMAND [ARGS]...
          A general utility script for Flask applications.
          .
        Options:
          --version  Show the flask version
          --help     Show this message and exit.
        Commands:
          hello   Just say hello.  # 我們注冊的自定義命令
          routes  Show the routes for the app.  # 顯示所有注冊的路由
          run     Runs a development server.
          shell   Runs a shell in the app context.

附注

關(guān)于自定義命令更多的設(shè)置和功能請參考Click的官方文檔(http://click.pocoo.org/6/)。

1.9 模板與靜態(tài)文件

一個完整的網(wǎng)站當(dāng)然不能只返回用戶一句“Hello,World!”,我們需要模板(template)和靜態(tài)文件(static file)來生成更加豐富的網(wǎng)頁。模板即包含程序頁面的HTML文件,靜態(tài)文件則是需要在HTML文件中加載的CSS和Java Script文件,以及圖片、字體文件等資源文件。默認(rèn)情況下,模板文件存放在項目根目錄中的templates文件夾中,靜態(tài)文件存放在static文件夾下,這兩個文件夾需要和包含程序?qū)嵗哪K處于同一個目錄下,對應(yīng)的項目結(jié)構(gòu)示例如下所示:

        hello/
            - templates/
            - static/
            - app.py

在開發(fā)Flask程序時,使用CSS框架和Java Script庫是很常見的需求,而且有很多擴(kuò)展都提供了對CSS框架和Java Script庫的集成功能。使用這些擴(kuò)展時都需要加載對應(yīng)的CSS和Java Script文件,通常這些擴(kuò)展都會提供一些可以在HTML模板中使用的加載方法/函數(shù),使用這些方法即可渲染出對應(yīng)的link標(biāo)簽和script標(biāo)簽。這些方法一般會直接從CDN加載資源,有些提供了手動傳入資源URL的功能,有些甚至提供了內(nèi)置的本地資源。

我建議在開發(fā)環(huán)境下使用本地資源,這樣可以提高加載速度。最好自己下載到static目錄下,統(tǒng)一管理,出于方便的考慮也可以使用擴(kuò)展內(nèi)置的本地資源。在過渡到生產(chǎn)環(huán)境時,自己手動管理所有本地資源或自己設(shè)置CDN,避免使用擴(kuò)展內(nèi)置的資源。這個建議主要基于下面這些考慮因素:

? 鑒于國內(nèi)的網(wǎng)絡(luò)狀況,擴(kuò)展默認(rèn)使用的國外CDN可能會無法訪問,或訪問過慢。

? 不同擴(kuò)展內(nèi)置的加載方法可能會加載重復(fù)的依賴資源,比如j Query。

? 在生產(chǎn)環(huán)境下,將靜態(tài)文件集中在一起更方便管理。

? 擴(kuò)展內(nèi)置的資源可能會出現(xiàn)版本過舊的情況。

關(guān)于模板和靜態(tài)文件的使用,我們將在第3章詳細(xì)介紹。

附注

CDN指分布式服務(wù)器系統(tǒng)。服務(wù)商把你需要的資源存儲在分布于不同地理位置的多個服務(wù)器,它會根據(jù)用戶的地理位置來就近分配服務(wù)器提供服務(wù)(服務(wù)器越近,資源傳送就越快)。使用CDN服務(wù)可以加快網(wǎng)頁資源的加載速度,從而優(yōu)化用戶體驗(yàn)。對于開源的CSS和Java Script庫,CDN提供商通常會免費(fèi)提供服務(wù)。

1.10 Flask與MVC架構(gòu)

你也許會困惑為什么用來處理請求并生成響應(yīng)的函數(shù)被稱為“視圖函數(shù)(view function)”,其實(shí)這個命名并不合理。在Flask中,這個命名的約定來自Werkzeug,而Werkzeug中URL匹配的實(shí)現(xiàn)主要參考了Routes(一個URL匹配庫),再往前追溯,Routes的實(shí)現(xiàn)又參考了Ruby on Rails(http://rubyonrails.org/)。在Ruby on Rails中,術(shù)語views用來表示MVC(Model-View-Controller,模型-視圖-控制器)架構(gòu)中的View。

MVC架構(gòu)最初是用來設(shè)計桌面程序的,后來也被用于Web程序,應(yīng)用了這種架構(gòu)的Web框架有Django、Ruby on Rails等。在MVC架構(gòu)中,程序被分為三個組件:數(shù)據(jù)處理(Model)、用戶界面(View)、交互邏輯(Controller)。如果套用MVC架構(gòu)的內(nèi)容,那么Flask中視圖函數(shù)的名稱其實(shí)并不嚴(yán)謹(jǐn),使用控制器函數(shù)(Controller Function)似乎更合適些,雖然它也附帶處理用戶界面。嚴(yán)格來說,F(xiàn)lask并不是MVC架構(gòu)的框架,因?yàn)樗鼪]有內(nèi)置數(shù)據(jù)模型支持。為了方便表述,在本書中,使用了app.route()裝飾器的函數(shù)仍被稱為視圖函數(shù),同時會使用“<函數(shù)名>視圖”(比如index視圖)的形式來代指某個視圖函數(shù)。

粗略歸類,如果想要使用Flask來編寫一個MVC架構(gòu)的程序,那么視圖函數(shù)可以作為控制器(Controller),視圖(View)則是我們第3章將要學(xué)習(xí)的使用Jinja2渲染的HTML模板,而模型(Model)可以使用其他庫來實(shí)現(xiàn),在第5章我們會介紹使用SQLAlchemy來創(chuàng)建數(shù)據(jù)庫模型。

1.11 本章小結(jié)

本章我們學(xué)習(xí)了Flask程序的運(yùn)作方式和一些基本概念,這為我們進(jìn)一步學(xué)習(xí)打下了基礎(chǔ)。下一章,我們會了解隱藏在Flask背后的重要角色——HTTP,并學(xué)習(xí)Flask是如何與之進(jìn)行交互的。

主站蜘蛛池模板: 阜康市| 罗江县| 洪江市| 渑池县| 渭南市| 盐池县| 天津市| 方正县| 诸城市| 溧阳市| 乌兰察布市| 武汉市| 米易县| 福建省| 辽阳县| 房山区| 西畴县| 平原县| 巴林左旗| 大兴区| 射阳县| 普洱| 九龙坡区| 杨浦区| 浪卡子县| 河源市| 津市市| 星座| 邓州市| 平果县| 和平区| 东乌珠穆沁旗| 扎囊县| 秦皇岛市| 丽水市| 芦溪县| 永平县| 轮台县| 天峻县| 军事| 东乡|