第二章 第一個程序,能有多難吶?
整個上一章沒寫一行代碼,現(xiàn)在你需要這個啦,對不?本章,我們將編寫第一個程序并逐行解釋。同時也包含如何設置開發(fā)環(huán)境,使用何種工具進行開發(fā),以及如何在程序中使用HTML。
Hello World程序
在學習新編程語言時,我們所寫的第一個程序通常都是HelloWorld,通過最小的代碼啟動一個程序并輸出文字"Hello World!"。讓我們也用Flask來實現(xiàn)它吧!
預備和工具
首先,確認一下我們正確配置了開發(fā)環(huán)境。本課程中,我假定你的操作系統(tǒng)是Debian類Linux發(fā)行版,如Mint(http://www.linuxmin.com),或者 Ubuntu(http://ubuntu.com)。其中所有的命令操作都將基于這些系統(tǒng)。
接下來,我們先通過apt-get命令安裝必需的Debian包:
sudo apt-get install python-dev python-pip
這將安裝python開發(fā)工具和編譯所需要的python庫,以及pip:一個靈巧耗用的工具,你可以用它通過命令行來安裝自己需要的python包。用起來吧!首先我們安裝一個環(huán)境管理工具:
sudo pip install virtualenvwrapper
echo "source /usr/local/bin/birtualenvwrapper.sh" >> ~/.bashrc
解釋一下上面的操作:sudo 告訴系統(tǒng)我們需要管理員權(quán)限來運行后面的命令,pip是默認的python包管理工具,可以幫我們安裝virtualenvwrapper包。第二個命令把命令添加到virtualenvwrapper.sh并加載到當前控制臺,以便于在當前shell中運行。
設置虛擬環(huán)境
所謂虛擬環(huán)境就是python用來隔離不同環(huán)境中的開發(fā)包的一種方法:它意味著你可以輕松的管理各類包依賴。想象一下,你要定義一個最小的只包含必要的開發(fā)包的項目,虛擬環(huán)境就可以完美地讓你進行測試和輸出必需的包。我們將在后面再研究它。現(xiàn)在,按下鍵盤上的Ctrl+Shift+T打開一個新的終端,創(chuàng)建我們的helloworld環(huán)境,如下:
mkvirtualenv hello
pip install flask
第一行,創(chuàng)建了名為'hello'的虛擬環(huán)境,且自動加載環(huán)境變量到當前終端。你可以輸入deactivate命令關(guān)閉它,也可以通過以下命令來加載激活這一環(huán)境:
workon hello #需要的話,用其它的環(huán)境名來替換hello
第二行告訴pip去安裝Flask包到當前虛擬環(huán)境里,在本例中是把flask包安裝到hello虛擬環(huán)境里。
理解“Hello World”程序
設定完虛擬環(huán)境,那我們用啥來編寫出漂亮的代碼呢?一個編輯器或者是一個IDE(集成開發(fā)環(huán)境)?如果你的預算低,那么可以嘗試一下LightTable editor編輯器(http://lighttable.com)。免費、快速并且易于使用(Ctrl+空格可以看到所有可用選項),并且它還支持工作空間。這個價格沒有更好的了。如果你很幸運有200美刀的預算(或者你擁有自由許可,那就不需要猶豫,直接入手PyCharm IDE吧(https://www.jetbrains.com/pycharm/buy/),它幾乎是最好的Python Web開發(fā)的IDE了?,F(xiàn)在,我們繼續(xù)。
創(chuàng)建一個文件夾來存放你的項目文件(不是必須的,但如果你這么做了,大家會更喜歡你的),如下:
mkdir hello_world
進入新文件夾后創(chuàng)建文件 main.py:
cd hello_world
touch main.py
main.py文件將包含整個“Hello World”程序代碼。其內(nèi)容應該如下所示:
#coding:utf-8
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__=="__main__":
app.run()
哇塞!就是敲了幾個字,對吧?不?哈哈好吧,我明白的。那么,我們剛才都做了什么?
第一行標明我們的main.py文件使用utf-8編碼??峄镉媯兌歼@么做,所以別對你的英語非母語的朋友太苛刻。在你的所有python文件中使用它(這樣可以在大型項目中幫你預防令人討厭的低級錯誤)。
第二行和第三行中,我們導入了Flask類并將其實例化。我們程序的名字是“app”。幾乎所有的都跟它(app)相關(guān)聯(lián):視圖(view)、藍圖(blueprint) ,配置(config)等等。“__name__”參數(shù)是必需的,用來告訴程序從何處查找資源,諸如靜態(tài)內(nèi)容或模板等。
為了創(chuàng)建“Hello World”,在用戶訪問web程序(使用瀏覽器或別的什么咚咚)的時候,我們需要告訴Flask實例如何應答。因此,F(xiàn)lask擁有叫做路由(route)的東西。
路由,就是是Flask讀取請求頭部并決定那個視圖(view,譯:Flask的視圖并不是MVC意義上的視圖view,而是類似MVC的控制器Controler)來應答此請求的方法。它首先分析被請求的URL的路徑部分,然后查找是哪個路由被注冊到這個路徑上。
在HelloWorld例子中,第五行,我們使用路由裝飾符來把hello函數(shù)注冊到根路徑("/")。每次當程序接收到路徑是“/”的請求時,hello函數(shù)就會被調(diào)用來應答這個請求。下面的片斷展示了如何檢查URL中的路徑:
from urlparse import urlparse
parsed = urlparse("http://www.google.com/")
assert parsed.path=="/"
你也可以將多個路由映射到同一個函數(shù)上,如下:
@app.route('/')
@app.route('/index')
def hello():
return "Hello World"
本例中,“/”和“/index”兩個路徑都被映射到hello視圖函數(shù)上。
第六行和第七行,我們完成了應答請求的函數(shù)。注意: 它沒有參數(shù)并且回復友好字符串。它之所以不需要參數(shù)是因為請求數(shù)據(jù)(如被提交的表單form)可以通過線程安全的變量“request”來訪問,這點我們將在上傳章節(jié)中進行詳細討論。
關(guān)于應答(response),F(xiàn)lask可以多種格式應答請求。在我們的例子中,我們以純文本應答,但我們還可以JSON或HTML格式應答。
第九行和第十行比較簡單,它們檢查main.py是以獨立腳本還是以模塊的形式被調(diào)用。如果是腳本,它就會運行內(nèi)建的開發(fā)服務器。讓我們試一下:
python main.py
你的終端將會有類似于下面的輸出:
Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
在你的瀏覽器中打開這個地址(http://127.0.0.1:5000/ )就會看到,我們的程序已經(jīng)正常工作了。
以腳本的形式調(diào)用main.py非常簡單、便于設置。通常,你只需要安裝Flask-Script擴展就可以調(diào)用開發(fā)服務器。
如果你把main.py作為模塊調(diào)用,只需要把它用如下代碼導入即可:
from main import what_I_want
在測試代碼的時候,你可能需要經(jīng)常這樣導入一個app的工廠函數(shù)。
這基本上就是我們“Hello World”程序全部需要解釋和理解的東西了。目前程序的缺憾就是沒有有趣的因素,所以讓我們添加上點東西,讓程序更有意思些。添加上HTML,CSS,和JavaScript可以更美觀些,讓我們試試吧。
響應HTML頁面
首先,要讓我們的hello函數(shù)用HTML應答,只需要做如下的更改:
def hello():
return "<html><head><title>Hi there!</title></head>
<body>Hello world!</body></html>",200
在上面的例子中,hello函數(shù)返回了HTML格式的字符串以及一個數(shù)字。字符串默認情況下被解析為HTML,而200則是表示應答成功的HTTP代碼。默認情況下也是返回200。
如果你按F5刷新瀏覽器,你將注意到頁面沒有變化。為什么呢?這是因為當源代碼變化的時候,F(xiàn)lask開發(fā)服務器沒有重新載入。只有當你打開程序的調(diào)試Debug模式時,才會自動重載。那么讓我們修改一下:
app=Flask(__name__)
app.debug=True
現(xiàn)在回到程序運行的終端,按下Ctrl+C組合鍵來重啟服務器(譯:windows下,ctrl+c只是停止服務器,需要重新輸入命令才能啟動。不知道ubuntu下是什么情況)。你將看到當服務器運行之后,在URL旁邊會出現(xiàn)一些新的信息輸出——類似于“restarting with stat”。這說明一旦代碼變更,服務器將自動重新加載之。這很棒,但你發(fā)現(xiàn)我們剛才犯下了罪行嗎:在處理響應的函數(shù)中直接定義了輸出模板?小心喲,MVC之神正在盯著你(譯:MVC模式要求將視圖,模型數(shù)據(jù),控制器三者分離)。讓我們把視圖從控制器中分離開吧。在項目文件夾中創(chuàng)建一個名為templates的文件夾,并在其中新建index.html文件。index.html文件內(nèi)容如下:
<html>
<head><title>Hi there!</title></head>
<body>
Hello world!
</body>
</html>
現(xiàn)在更改你的main.py代碼如下:
#coding:utf-8
from flask import Flask,render_template
@app.route("/")
def hello():
return render_template("index.html")
你明白我們做了什么嗎?render_template的功能就是從templates/文件夾(Flask的默認模板文件夾)中加載模板,你可以返回輸出來渲染它。
現(xiàn)在讓我們添加一些JavaScript和CSS樣式。默認情況下,F(xiàn)lask內(nèi)建的開發(fā)服務器會從你的項目文件夾下的static子文件夾中搜索。我們創(chuàng)建并添加文件到其中,你的項目文件夾層次應該如下所示:
project/
--main.py
--templates/
----index.html
--static/
----js
------jquery.min.js
------foundation.min.js
------modernizr.js
----css
------styles.css
------foundation.min.css
注意,我從foundation.zurb框架(一個很好的css框架你可以從http://foundation.zurb.com/獲得)中添加了文件。我建議你也這么做,可以輕松獲得一個現(xiàn)代化的,漂亮的站點。你模板中的靜態(tài)文件路徑應該看其來如下:
<script src='/statc/js/modernizr.js'></script>
這個文件夾/static前面的真實路徑默認是Flask在調(diào)試模式下調(diào)用。如果是實際生產(chǎn)模式下,你就必須使用獨立的http服務器來提供靜態(tài)文件。你可以查看本章最后的附加完整代碼。
試著使用更好的CSS樣式來改進hello world例子。
總計
設置開發(fā)服務器是一個非常重要的任務,我們完成了。創(chuàng)建“Hello World”程序是介紹一項新技術(shù)最好的辦法,我們也完成了。最后我們學到了如何生成HTML頁面并使用靜態(tài)文件,基本上就是大部分web程序做的。在本章你學到了所有技術(shù),我希望這個過程很輕松并且讓你滿意。
在下章中,我們添加一點挑戰(zhàn)性的調(diào)味汁,設置更高級的模板。我們將學習如何使用Jinja2包來創(chuàng)建更棒的模板,并允許我們用最少的輸入做的更多。
再會吧!