簡單而直接的Python web 架構:web.py

來源:互聯網
上載者:User

From:https://www.oschina.net/question/5189_4306

Web.py github 地址:https://github.com/webpy/webpy        https://pypi.python.org/pypi/web.py

Web.py Cookbook 簡體中文版:http://webpy.org/cookbook/index.zh-cn

web.py 0.3 新手指南:http://webpy.org/docs/0.3/tutorial.zh-cn

webpy 官網文檔:http://webpy.org/

web.py 十分鐘建立簡易部落格:http://blog.csdn.net/freeking101/article/details/53020728

一個簡單的web.py論壇:http://www.cnblogs.com/russellluo/p/3240564.html


web.py 是一個Python 的web 架構,它簡單而且功能強大。web.py 是公開的,無論用於什麼用途都是沒有限制的。而且相當的小巧,應當歸屬於輕量級的web 架構。但這並不影響web.py 的強大,而且使用起來很簡單、很直接。在實際應用上,web.py 更多的是學術上的價值,因為你可以看到更多web 應用的底層,這在當今“抽象得很好”的web 架構上是學不到的 :) 如果想瞭解更多web.py,可以訪問web.py 的官方文檔。

先感受一下web.py 的簡單而強大:

import weburls = (    '/(.*)', 'hello')app = web.application(urls, globals())class hello:    def GET(self, name):        i = web.input(times=1)        if not name:             name = 'world'        for c in xrange(int(i.times)):             print 'Hello,', name+'!'        return 'Hello, ' + name + '!'if __name__ == "__main__":    app.run()

上面就是一個基於web.py 的完整的Web 應用程式。將上面的代碼儲存為檔案code.py,在命令列下執行python code.py。然後開啟你的瀏覽器,開啟地址:http://localhost:8080 或者 http://localhost:8080/test 沒有意外的話(當然要先安裝web.py,下面會有介紹),瀏覽器會顯示“Hello, world”或者 “Hello, test”。



Linux 下運行


這是一個最簡單的Hello world Web 應用程式。是不是很簡單。。下面將較為詳細地介紹下web.py 。


1. 安裝

下載 web.py 的安裝檔案,將下載得到的檔案 web.py 解壓,進入解壓後的檔案夾,在命令列下執行:python setup.py install,在Linux 等系統下,需要root 的許可權,可以執行:sudo python setup.py install。


2. URL 處理

對於一個網站來說,URL 的組織是最重要的一個部分,因為這是使用者看得到的部分,而且直接影響到網站是如何工作的,例如:www.baidu.com ,其URLs 甚至是網頁介面的一部分。而web.py 以簡單的方式就能夠構造出一個強大的URLs。

在每個web.py 應用,必須先import web 模組:

import web

現在,我們須要告訴web.py URL 如何組織,讓我們以一個簡單例子開始:

urls = (  '/', 'index'    )

在上面的例子中,第一部分是匹配URL的Regex,像/、/help/faq、/item/(\d+)等(\d+將匹配數字)。圓括弧表示捕捉對應的資料以便後面使用。第二部分是接受請求的類名稱,像index、view、welcomes.hello(welcomes模組的hello類),或者get_\1。\1 會被Regex捕捉到的內容替換,剩下來捕捉的的內容將被傳遞到你的函數中去。(‘index’)是一個類名,匹配的請求將會被發送過去。這行表示我們要URL/(首頁)被一個叫index的類處理。

現在我們需要建立一個列舉這些 url 的 application。

app = web.application(urls, globals())


GET 和 POST : 區別

現在,我們需要編寫index 類。當大部人瀏覽網頁的時候,他們都沒有注意到,瀏覽器是通過HTTP 跟World Wide Web 通訊的。通訊的細節不太重要,但要明白一點,使用者是通過URLs(例如 / 或者 /foo?f=1)來請求網頁伺服器完成一定請求的(例如 GET 或者POST)。

GET 是最普遍的方法,用來請求一個頁面。當我們在瀏覽器裡輸入“harvard.edu” 的時候,實際上它是向Web 服務器請求GET ”/“。另一個常見的方法是POST,常用於提交特定類型的表單,比如請求買什麼東西。每當提交一個去做什麼事情(像使用信用卡處理一筆交易)的請求時,你可以使用POST。這是關鍵,因為GET的URL可以明文傳輸提交的參數。如果提交的是一些重要的敏感資訊,例如使用者名稱,密碼,則可能被別人抓包擷取到。而 POST 則不會在 URL 上傳輸 提交的資訊,POST 是通過表單提交資訊。

在我們的web.py 代碼中。我們清晰區分這兩種方法:

class index:    def GET(self):        print "Hello, world!"

當接收到一個GET 請求時,上面的GET 方法將會被web.py 調用。好的。現在,我們只需添加最後一行代碼,讓web.py 啟動網頁應用:

if __name__ == "__main__":    app.run()

上面告訴web.py 如何配置URLs,以及找尋的類在檔案中的全域命名空間。然後為我們啟動上面的應用。

整個 code.py 檔案的內容如下:

import weburls = (    '/(.*)', 'hello')app = web.application(urls, globals())class hello:    def GET(self, name):        i = web.input(times=1)        if not name:             name = 'world'        for c in xrange(int(i.times)):             print 'Hello,', name+'!'        return 'Hello, ' + name + '!'if __name__ == "__main__":    app.run()

實際上web 應用的代碼就只得上面的幾行,而且這是一個完整的web.py 應用。


3.啟動服務

在你的命令列下輸入:

$ python code.py                               # 使用預設連接埠 8080或者$ python code.py 10000                         # 改變連接埠為 10000

你的web.py 應用已經啟動了伺服器。通過瀏覽器訪問:http://localhost:8080/ ,會見到”Hello, world。“。


修改預設連接埠

在啟動伺服器的時候,如果你不想使用預設連接埠,你可以使用這樣的命令來指定連接埠號碼: python code.py 8888。


4. 調試

直接添加一行 web.internalerror = web.debugerror 即可。如下

if __name__=="__main__":    web.internalerror = web.debugerror    app.run()


5. 模板

更多關於 web.py templates 可以訪問    http://webpy.org/docs/0.3/templetor.zh-cn

在Python 裡面編寫HTML 程式碼是相當累贅的,而在HTML 裡嵌入Python 代碼則有趣得多。幸運地,web.py 使這過程變得相當容易。

注意:舊版本的web.py 是用Cheetah templates 模板的,你可以繼續使用,但官方已不再提供支援。

建立一個 code.py 的 python檔案。內容如下:

import weburls = (    # '/(.*)', 'hello',    '/hello_1[/]?.*', 'hello_1',    '/hello_2/(.*)', 'hello_2',)app = web.application(urls, globals())render=web.template.render('templates')class hello_1:    def GET(self):                return render.index_1() class hello_2:    def GET(self, name):                return render.index_2("Lisa")         if __name__ == "__main__":    app.run()


建立模板

這裡,我們先在項目 code.py 同一級目錄中建立一個目錄(例如 templates )集中存放並用來組織模板檔案,便於管理。然後在templates下建立HTML 檔案(例如:”index.html“)。這裡建立 兩個 HTML 檔案。 index_1.html 和 index_2.html


index_1.html 檔案內容如下:

<em>Hello</em>, world!

這是一個最簡單的html頁面代碼。

index_2.html 檔案內容如下:

$def with (name)<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head>    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    <title>Template</title></head><body>    Hi, $name</body></html>

注意上面代碼的縮排。

正如你所見的,上面的模板看上去跟這Python 檔案很相似,以def with 語句開始,但在關鍵字前需要添加”$“。

注意:在模板內的變數,如果包含有HTML 標籤,以$ 方式引用變數的話,HTML 標籤只會以純文字的顯示出來。要想HTML 標籤產生效果,可以用$: 引用變數。


使用模板

現在,回到 code.py 檔案,在”import web” 的下一行添加:

render = web.template.render('templates/')

這告訴web.py 在哪裡可以搜尋得到模板目錄。提示:可在render 調用裡添加cache = False 使得每次訪問頁面時都重載模板。

然後再修改使用這個模板的類,在這裡  修改 類 hello_1 和 類 hello_2

class hello_1:    def GET(self):        return render.index_1() class hello_2:    def GET(self, name):        # name = "Lisa"        return render.index_2("Lisa") 

上面的 ”index_1“ 和 “index_2” 是模板的名字,”Lisa“ 是傳遞過去的參數。

同時修改urls為:

urls = (    # '/(.*)', 'hello',    '/hello_1[/]?.*', 'hello_1',    '/hello_2/(.*)', 'hello_2',)

上面的“/(.*)” 是一個Regex。括弧裡面是要傳遞的參數。再將GET 方法修改如下:

def GET(self,name):    print render.index_2(name)

hello_1 頁面調用 hello_1 類,使用 index_1.html 模板。開啟 http://localhost:8080/hello_1 ,頁面就會列印出 Hello, world 的字樣。

hello_2/ 頁面調用 hello_2 類,使用 index_2.html 模板,開啟 http://localhost:8080/hello_2/,頁面就會列印出 Hello, Lisa 的字樣。



除此之外還有兩種使用模板的方法 使用frender直接指定模板檔案。GET函數最後兩行改為

  render=web.template.frender("templates/index.html")  return render("Lisa")
直接在代碼裡寫出模板檔案。GET最後兩行改為
  template = "$def with (name)\nHello $name"  render = web.template.Template(template)  return render("Lisa")


模板含義

現在解釋一下這個 index.html 模板的含義:

$def with (name)<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head>    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    <title>Template</title></head><body>    Hi, $name</body></html>

在index.html第一行 $def with (name)表示本模板接受一個名為name的參數,也就是對應index類中return render.index(“Lisa”)中的Lisa。

而render=web.template.render(“templates”)表示建立一個模板對象,模板是存放於templates目錄下,然後就可以用所建立的 render 對象來訪問相應的模板

比如templates目錄下的index.html就是用render.index來表示(實際上是匹配尋找index.*檔案,第一個匹配的就認為是所對應的模板檔案),如果templates下還有個a目錄,a目錄下有個pagea.html,那麼訪問這個pagea模板就要用render.a.pagea的形式了。


頁面參數

頁面接收的參數可以多於一個,也可以沒有,如果不需要參數,則就不需要$def with (name)這樣的代碼,刪除掉這一句,同時修改模板中對name變數的引用,修改index類最後一句為return render.index()就可以了。

如果有參數,那麼模板的第一行代碼就必須是這個 $def with (…),可以多於一個參數,比如是這樣$def with (gname, fname)。

模板下面的那行字改為Hi, $gname $fname。

同時Index類GET返回的時候賦予對應兩個參數return render.index(“Lisa”,”Hayes”)。

這樣,頁面最後顯示的是列印出Hi, Lisa Hayes的字樣。

另外,模板接受的這個參數也可以是一個元組,比如像下面這樣:return render.index((“Lisa”,”Hayes”))

在模板中可以如下以元組方式訪問參數資料:Hi, $name[0] $name[1]


模板文法

模板文法與python文法基本一致,主要差別可以從上面的代碼中看到,要使用到$符號表明這不是文本而是模板代碼。也就是每當用到程式碼、對象的時候就必須用$來與html代碼和頁面顯示文本相區別。


對象賦值

向對象賦值時需要在$與對象名之間留空格,如為一個名為vara的字串對象賦值apple的代碼為$ vara = “apple”。
另外,對象指派陳述式必須獨佔一行,前面或後面有其他代碼則會程式出錯。


對象引用

引用對象的時候直接使用 $+對象名的形式,如$vara。
另外引用對象時還可以用{}或()將對象進行明確的分組,如$(vara)s就會表示apples,如果沒有括弧,程式則會把 $varas作為一個整體,也就變成對varas對象的引用而發生錯誤。另如果像如下定義兩個數字型對象:

$varb = 1$varc = 2

然後希望計算兩個值的和,如果用$varb+$varc的形式,頁面上只會得到1+2而不是3,這時也就需要把兩個對象放在括弧裡,如$(varb+varc)的形式才能得到正確答案3。


注釋

模板中支援單行注釋,以$#符號開始到行末都是注釋內容。
$#This is comment
注釋前面可以有其他內容,但是不可以有賦值代碼。
如下代碼是正確的:Hi $#This is comment
但下面的則會出錯:$ vara = “apple” $#This is comment


列印$符號

由於$符號在模板中有特殊用途,所以在頁面上輸出$時需要進行轉義操作,用連續兩個$表示在頁面上輸出一個$符號。

Can you lend me $50?


控制碼(迴圈、條件判斷)

模板中支援for、while、if、elif、else,用法與在python一致,只是控制碼行要以$開始(包括break和continue命令),$開始的程式碼中對象不需要在前面再加$符號,同時要注意縮排規則,如:

for 迴圈:

$def with (toUser,fromUser,createTime,articleCnt,articles)<xml>    <ToUserName><![CDATA[$toUser]]></ToUserName>    <FromUserName><![CDATA[$fromUser]]></FromUserName>    <CreateTime>$createTime</CreateTime>    <MsgType><![CDATA[news]]></MsgType>    <ArticleCount>$articleCnt</ArticleCount>    <Articles>        $for a in articles:            <item>                <Title><![CDATA[$a['title']]]></Title>                <Description><![CDATA[$a['desc']]]></Description>                <PicUrl><![CDATA[$a['picUrl']]]></PicUrl>                <Url><![CDATA[$a['url']]]></Url>            </item>    </Articles></xml>

if else判斷:

$if times > max:    Stop! In the name of love.$else:    Keep on, you can do it.

在for迴圈中,有一組內建的變數可以使用,非常方便,分別如下所示: loop.index: 迴圈次數計數 (1-開始) loop.index0: 迴圈次數計數(0-開始) loop.first: 如果是第一次迴圈則為True loop.last: 如果是最後一次迴圈則為True loop.odd: 如果是第奇數次迴圈則為True loop.even: 如果是第偶數次迴圈則為True loop.parity: 如果迴圈次數為奇數值為“odd” ,反之為 “even” loop.parent: 本迴圈的外層迴圈對象

$for a in ["a", "b", "c", "d"]:     $loop.index,$loop.index0,$loop.first,$loop.last,$loop.odd,$loop.even,$loop.parity<br/>

將在頁面上列印出:

1,0,True,False,True,False,odd2,1,False,False,False,True,even3,2,False,False,True,False,odd4,3,False,True,False,True,even


函數-$def

函數定義也是與在python中類似,用def,只是也要在前面加$,代碼也要注意$的使用和縮排:

$def hello(name=""):Hello $name!
函數調用也是用$加函數名的形式:
$hello("Lisa")
當然,定義函數時也可以與html代碼混編:
$def hello(name=""):<strong/>Hello $name!</strong>
但是調用的時候需要在函數名前用$:首碼,否則html代碼將以plain text形式列印到頁面上。
$:hello("Lisa")


輸出程式碼-$code塊

如果想在模板裡輸入寫一段python代碼而又不想被$所煩惱,那麼可以用到$code塊。

頁面上輸出一段代碼而不希望被系統理解為模板程式碼,就需要用到$code命令,比如在模板檔案中寫入下面一段:

$code:    x=10    def print_num(num):    return "num is %d" % num

然後再加上下面代碼:

$print_num(x)<br/>$x

這裡就用在$code塊中定義的print_num函數以x變數為參數在頁面上輸出一行:num is 10

然後下一行直接引用x變數,直接在頁面上輸出數字10。


$var

$var命令可以在模板中定義變數,在其他地方引用此模板對象的時候可以訪問此定義的變數。
比如我們可以在index.html中添加如下一行:$var vara: this is vara
表示定義了一個名為vara的變數,變數值是字串this is vara。
把index的GET函數改為:

def GET(self):    render=web.template.render("templates")    return render.index("Lisa", "Hayes").vara

那麼結果顯示在頁面上的就是this is vara這句話。要注意一點的是,這種變數是字串,即便如下定義變數:$var vara: 0

Vara也並不是數字0,如果把GET函數最後改成:return render.index(“Lisa”, “Hayes”).vara+1

會導致程式出錯。如果希望得到期望中的結果1,則需要如下形式代碼:return int(render.index(“Lisa”, “Hayes”).vara)+1


builtins and globals

在模板中,使用者可以直接使用python的內建函數和變數,寫函數變數包括range, min, max 以及 True 和 False等。 除此之外,如果希望在模板中使用其他的非內建功能,就需要一點特殊操作。要在建立render的時候顯式指定所需要的功能函數。

import webimport markdownglobals = {'markdown': markdown.markdown}render =web.template.render('templates', globals=globals)

這樣,在模板中就可以用$markdown來引用markdown.markdown了。同樣,也可以用這種辦法來禁用builtins

# disable all builtinsrender = web.template.render('templates', builtins={})


模板複用

當多個頁面有著相同的結構架構的時候,為每一個頁面單獨維護一個模板就顯得比較麻煩,web.py提供了一種簡易的解決方案。
這時候就要用到建立render時使用base參數:

render=web.template.render("templates",base="layout")return render.index("Lisa", "Hayes")

這個layout表示要以templates下的layout.html模板為通用模板架構。因此我們還要在templates目錄下建立一個layout.html檔案,寫下如下代碼:

$def with (content)    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">    <html xmlns="http://www.w3.org/1999/xhtml">    <head>        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />        <title>Layout</title>    </head>    <body>        $:content    </body></html>
可以看到,這個模板檔案必須是有一個參數content。然後修改index.html,只保留如下代碼,其他刪掉:
$def with(gname, fname)    Hi, $(gname) $(fname)

運行程式,頁面上列印Hi, Lisa Hayes,查看代碼會發現最終代碼就是index.html和layout.html合并在一起的結果,index.html中的內容被嵌入到layout.html中的$:content處。
在layout.html模板中還可以引用index.html中定義的var變數,這為程式帶來了更多的靈活性,比如我們希望在不同的頁面在使用同一個layout模板的時候能有不同的title,可以在使用layout的模板中定義如下一個var變數:$var title:This is index.html
然後在layout.html中的title處修改為:<title>$content.title</title>
這樣,訪問index.html時顯示在瀏覽器上的title就是This is index.html,而不是原來的Layout了。


在模板中使用python代碼模組

在預設狀態下,在模板中是不能直接調用其他python代碼模組檔案中的程式的,必須做一些額外的操作。
首先,我們建立一個模組,叫module1.py,在裡面寫一個函數:

def hello_from_m1(name=""):    return "hello %s, this is module1" % name

在main.py裡匯入module1:import module1

並且修改GET函數中建立render的代碼為:

def GET(self):    render=web.template.render("templates",base="layout",globals={"m1":module1})    return render.index("Lisa")

globals參數中傳遞的是一個字典,key以字串表示模組在模板中使用時的名稱,value部分就是這個要在模組中使用的模組或對象的真實名稱了。
最後在要使用此模組的模板中就可以用$m1來引用此模組了。比如在index.html中添加下面一行代碼:$m1.hello_from_m1(gname)
就會調用module1中的hello_from_m1函數,在頁面上列印出:hello Lisa, this is module1


在web.py模板中使用jQuery

在jQuery中$也是一個關鍵字,這樣的話如果在模板中使用jQuery就會衝突,這時候只需要用$做一下轉義就可以了,比如:

<script type="text/javascript">$(document).ready(function(){    alert("It works.");});</script>


6. 資料庫


Web.py 更多關於資料庫的操作:http://webpy.org/cookbook/index.zh-cn

注意:在你開始串連資料庫之前,請先安裝正確的資料庫驅動。比如 MySQLdb、psycopg2。如果需要嘗試串連 池(database pool)功能,還得裝下DBUtils。這幾個模組都可以通過easy_install 或者 pip 來安裝。

串連資料庫:

import webdb = web.database(dbn='postgres', db='mydata', user='dbuser', pw='')

操作 資料庫 樣本

select 查詢# 查詢表entries = db.select('mytable')     # where 條件myvar = dict(name="Bob")results = db.select('mytable', myvar, where="name = $name")results = db.select('mytable', where="id>100")# 查詢具體列results = db.select('mytable', what="id,name")# order byresults = db.select('mytable', order="post_date DESC")# groupresults = db.select('mytable', group="color")# limitresults = db.select('mytable', limit=10)# offsetresults = db.select('mytable', offset=10)更新db.update('mytable', where="id = 10", value1 = "foo")刪除db.delete('mytable', where="id=10")複雜查詢# countresults = db.query("SELECT COUNT(*) AS total_users FROM users")print results[0].total_users# joinresults = db.query("SELECT * FROM entries JOIN users WHERE entries.author_id = users.id")# 防止SQL注入可以這麼幹results = db.query("SELECT * FROM users WHERE id=$id", vars={'id':10})多資料庫操作 (web.py大於0.3)db1 = web.database(dbn='mysql', db='dbname1', user='foo')db2 = web.database(dbn='mysql', db='dbname2', user='foo')print db1.select('foo', where='id=1')print db2.select('bar', where='id=5')事務t = db.transaction()try:    db.insert('person', name='foo')    db.insert('person', name='bar')except:    t.rollback()    raiseelse:    t.commit()# Python 2.5+ 可以用withfrom __future__ import with_statementwith db.transaction():
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.