python模擬Django框架實例
一、python實現(xiàn)web服務(wù)器
web開發(fā)首先要有web服務(wù)器才行。比如apache,但是在開發(fā)階段最好有一個簡單方便的開發(fā)服務(wù)器,
容易重啟進(jìn)行調(diào)試,等開發(fā)調(diào)試完畢后,再將代碼部署到成熟穩(wěn)定高效的web服務(wù)器。
# -*- coding: utf-8 -*- from wsgiref import simple_server # 定義一個輸出 hello world 和環(huán)境變量的簡單web應(yīng)用程序 def hello_app(environ, start_response): # 輸出 http 頭,text/plain 表示是純文本 start_response('200 OK', [('Content-type','text/plain')]) # 準(zhǔn)備輸出的內(nèi)容 content = [] content.append('Hello world') for key, value in environ.items(): content.append('%s : %s' % (key, value)) # 輸出,根據(jù) wsgi 協(xié)議,返回的需要是一個迭代器,返回一個 list 就可以 return ['\n'.join(content)] # 構(gòu)造開發(fā)服務(wù)器對象,設(shè)置綁定的地址和端口,并把 hello world 應(yīng)用程序傳給他 server = simple_server.make_server('localhost', 8080, hello_app) # 啟動開發(fā)服務(wù)器 server.serve_forever()
執(zhí)行上面這個程序后,打開瀏覽器,訪問一個以 http://localhost:8080 開頭的網(wǎng)址即可看到 environ 所包含的內(nèi)容。
(截取一小部分)
二、基礎(chǔ)知識
瀏覽器和web應(yīng)用之間使用的是http協(xié)議,它規(guī)定了請求和響應(yīng)的格式。
1、請求包(Http Request)
請求主要包括請求的方法,請求的URL,請求頭,請求體。
請求的方法http規(guī)定有GET, POST, PUT, DELETE,只不過通過瀏覽器發(fā)起的web請求一般只涉及GET和POST請求。
GET一般用來獲取服務(wù)器內(nèi)容,POST類似修改內(nèi)容,PUT添加,DELETE刪除。
一般通過提交html的form表單發(fā)起POST請求。成功后需要進(jìn)行重定向。
從協(xié)議上看GET,HTTP請求最大的區(qū)別就是GET請求沒有請求體,而POST請求有。這就意味著可以通過POST請求
向服務(wù)器發(fā)送大量數(shù)據(jù),如上傳文件等,當(dāng)然GET請求也可以通過URL本身以及其參數(shù)向服務(wù)器傳遞參數(shù),比如
url?arg1=value&arg2=value
請求頭就是包含了請求包的描述信息。 比如編碼,包長度等。
2、響應(yīng)包(Http Response)
http的響應(yīng)包的格式更簡單一些,包括狀態(tài)碼,響應(yīng)頭和響應(yīng)體,狀態(tài)碼表示該請求的結(jié)果,比如
200表示成功
404表示資源沒有找到
500表示服務(wù)器錯誤
301表示資源已經(jīng)換了地址,客戶端需要跳轉(zhuǎn)。
響應(yīng)頭和請求頭類似,包括一些描述信息,響應(yīng)體一般就是輸出內(nèi)容了,大部分是頁面html代碼。
3、請求的生命周期
1. web服務(wù)器接收到原始的http請求后進(jìn)行一定程度的包裝再交給web應(yīng)用程序
2. web應(yīng)用程序處理后,再以一定的格式返回數(shù)據(jù)給web服務(wù)器
3. web服務(wù)器再將數(shù)據(jù)包裝成http響應(yīng)包返回給瀏覽器。
4、關(guān)于cgi
cgi(common gateway interface)就是web服務(wù)器與web應(yīng)用程序之間的一個古老的協(xié)議,在cgi協(xié)議中,
web服務(wù)器將http請求的各種信息放到cgi應(yīng)用程序的環(huán)境變量中,cgi應(yīng)用程序再通過標(biāo)準(zhǔn)輸出,輸出它的響應(yīng)頭
和相應(yīng)內(nèi)容給web服務(wù)器。
上面用到的開發(fā)服務(wù)器與應(yīng)用程序之間所使用的協(xié)議叫做wsgi,它和cgi類似,同樣將請求包裝成一種key-value對,
只不過cgi通過環(huán)境變量傳給cgi應(yīng)用程序,而wsgi直接使用python的字典對象來傳遞。
hello_app的第一個參數(shù)environ就是包含請求信息的字典對象,第二個參數(shù)是個函數(shù),web應(yīng)用程序在輸出響應(yīng)內(nèi)容
前需要先調(diào)用它來輸出狀態(tài)碼和響應(yīng)頭。
處理web請求和響應(yīng)這里使用webob模塊來處理請求和響應(yīng),需要安裝,這里首先要安裝setuptools模塊,一個包管理的工具,可以通過這個工具自動下載需要的軟件包,類似ubuntu的app-get。下面是地址:http://pypi.python.org/pypi/setuptools安裝結(jié)束,可以直接在命令行中輸入:easy_install webob這樣就會自動下載安裝。
簡單使用:
>>> # 導(dǎo)入 Request 對象
>>> from webob import Request
>>> environ = {}
>>> # 使用 Request 來包裝 environ 字典
>>> req = Request(environ)
使用一個Request類來包裝environ,然后通過Request對象的屬性和方法對environ進(jìn)行訪問。由于只有在一個web環(huán)境才能得到一個真實的environ字典,為了方便大家在shell中進(jìn)行測試,webob提供了一個模擬簡單web請求的方法:
也可以通過req查找其它有用的信息
同時也可以通過webob模塊中的Response對象來包裝響應(yīng)信息。
下面使用webob模塊重寫之前的hello_app
# -*- coding: utf-8 -*- from wsgiref import simple_server from webob import Request, Response # 我們順便增加了一個功能,就是根據(jù)用戶在 URL 后面?zhèn)鬟f的參數(shù) # 顯示相應(yīng)的內(nèi)容 def hello_app(request): content = [] # 獲取 get 請求的參數(shù) content.append('Hello %s'%request.GET['name']) # 輸出所有 environ 變量 for key, value in request.environ.items(): content.append('%s : %s' % (key, value)) response = Response(body='\n'.join(content)) response.headers['content-type'] = 'text/plain' return response # 對請求和響應(yīng)進(jìn)行包裝 def wsgi_wrapper(environ, start_response): request = Request(environ) response = hello_app(request) # response 對象本身也實現(xiàn)了與 wsgi 服務(wù)器之間通訊的協(xié)議, # 所以可以幫我們處理與web服務(wù)器之間的交互。 # 這一句比較奇怪,對象使用括號是什么意思。。。。 return response(environ, start_response) server = simple_server.make_server('localhost', 8080, wsgi_wrapper) server.serve_forever()
為了讓 wsgi_wrapper 更加通用一點,可以把它設(shè)計成裝飾器的形式:
# -*- coding: utf-8 -*- from wsgiref import simple_server from webob import Request, Response # 寫成裝飾器的 wsgi_wrapper def wsgi_wrapper(func): def new_func(environ, start_response): request = Request(environ) response = func(request) return response(environ, start_response) new_func.__name__ = func.__name__ new_func.__doc__ = func.__doc__ return new_func # 應(yīng)用程序 @wsgi_wrapper def hello_app(request): content = [] content.append('Hello %s'%request.GET['name']) for key, value in request.environ.items(): content.append('%s : %s' % (key, value)) response = Response(body='\n'.join(content)) response.headers['content-type'] = 'text/plain' return response server = simple_server.make_server('localhost', 8080, hello_app) server.serve_forever()
三、模板
果然,還是需要用到模板,不能總是直接在Response中寫上長串的html代碼。
python中的模板引擎主要有mako, genshi, jinjia等。
mako 主要特點在于模板里面 可以比較方便的嵌入Python代碼,而且執(zhí)行效率一流;
genshi 的特點在于基于 xml, 非常簡單易懂的模板語法,對于熱愛xhtml的朋友來說是很好的選擇,
同時也可以嵌入Python 代碼,實現(xiàn)一些復(fù)雜的展現(xiàn)邏輯;
jinja 和genshi 一樣擁有很簡單的模板語法,只是不 依賴于 xml 的格式,同樣很適合設(shè)計人員直接進(jìn)行模板的制作,
同時也可以嵌入Python 代碼實現(xiàn)一些復(fù)雜的展現(xiàn)邏輯。
這里使用Mako,地址http://pypi.python.org/pypi/Mako,下載python setup.py install進(jìn)行安裝
簡單的模塊例子:
## -*- coding: utf-8 -*- <html> <head> <title>簡單mako模板</title> </head> <body> <h5>Hello ${name}!</h5> <ul> % for key, value in data.items(): <li> ${key} - ${value} <li> % endfor </ul> </body> </html>
保存為simple.html文件,然后需要給模板對象傳遞data和name兩個參數(shù),然后進(jìn)行渲染,就可以輸入html內(nèi)容
# -*- coding: utf-8 -*- # 導(dǎo)入模板對象 from mako.template import Template # 使用模板文件名構(gòu)造模板對象 tmpl = Template(filename='./simple.html', output_encoding='utf-8') # 構(gòu)造一個簡單的字典填充模板,并print出來 print tmpl.render(name='python', data = {'a':1, 'b':2})
保存為test_template.py文件,運行就可以輸入內(nèi)容:
$ python test_template.py
<html> <head> <title>簡單mako模板</title> </head> <body> <h5>Hello python!</h5> <ul> <li> a - 1 <li> <li> b - 2 <li> </ul> </body> </html>
下面對hello_app程序進(jìn)行重構(gòu):
1. 把 wsgi_wrapper 單獨放到通用模塊 utils.py:
# -*- coding: utf-8 -*- from webob import Request def wsgi_wrapper(func): def new_func(environ, start_response): request = Request(environ) response = func(request) return response(environ, start_response) new_func.__name__ = func.__name__ new_func.__doc__ = func.__doc__ return new_func
2. 把 hello_app 給徹底獨立出來,形成單獨的模塊 controller.py :
# -*- coding: utf-8 -*- from utils import wsgi_wrapper from webob import Response from mako import Template # 整合了模板功能的 hello_app @wsgi_wrapper def hello_app(request): tmpl = Template(filename='./simple.html', output_encoding='utf-8') content = tmpl.render(name=request.GET['name'], data=request.environ) return Response(body=content)
3. 這樣 main.py 就變成這樣了:
# -*- coding: utf-8 -*- from wsgiref import simple_server from controller import hello_app server = simple_server.make_server('localhost', 8080, hello_app) server.serve_forever()
四、ORM(Object Relation Mapping, 對象關(guān)系映射)
終于也要這一步了,作為web應(yīng)用,還是需要與數(shù)據(jù)庫進(jìn)行合作。
這里使用sqlalchemy,是一個 ORM (對象-關(guān)系映射)庫,提供Python對象與關(guān)系數(shù)據(jù)庫之間的映射。和Django的models
用法很像,也是可以通過python代碼來創(chuàng)建數(shù)據(jù)庫表,并進(jìn)行操作。
sqlalchemy 還可以自動映射 Python 對象的繼承,可以實現(xiàn)eager loading、lazy loading, 可以直接將 Model 映射到自定
義的 SQL 語句,支持n多的數(shù)據(jù)庫等等等等。 可以說 sqlalchemy 既有不輸于 Hibernate 的強(qiáng)大功能,同時不失 Python
的簡潔優(yōu)雅。
使用方法:
# -*- coding: utf-8 -*- from sqlalchemy import * from sqlalchemy.orm import sessionmaker, scoped_session from sqlalchemy.ext.declarative import declarative_base # 創(chuàng)建數(shù)據(jù)庫引擎,這里我們直接使用 Python2.5 自帶的數(shù)據(jù)庫引擎:sqlite, # 直接在當(dāng)前目錄下建立名為 data.db 的數(shù)據(jù)庫 engine = create_engine('sqlite:///data.db') # sqlalchemy 中所有數(shù)據(jù)庫操作都要由某個session來進(jìn)行管理 # 關(guān)于 session 的詳細(xì)信息請參考:http://www.sqlalchemy.org/docs/05/session.html Session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) Base = declarative_base() class Dictionary(Base): # Python 對象對應(yīng)關(guān)系數(shù)據(jù)庫的表名 __tablename__ = 't_dictionary' # 定義自動,參數(shù)含義分別為:數(shù)據(jù)庫字段名,字段類型,其他選項 key = Column('key', String(255), primary_key=True) value = Column('value', String(255)) # 創(chuàng)建數(shù)據(jù)庫 Base.metadata.create_all(engine) session = Session() for item in ['python','ruby','java']: # 構(gòu)造一個對象 dictionary = Dictionary(key=item, value=item.upper()) # 告訴 sqlalchemy ,將該對象加到數(shù)據(jù)庫 session.add(dictionary) # 提交session,在這里才真正執(zhí)行數(shù)據(jù)庫的操作,添加三條記錄到數(shù)據(jù)庫 session.commit() # 查詢數(shù)據(jù)庫中Dictionary對象對應(yīng)的數(shù)據(jù) for dictionary in session.query(Dictionary): print dictionary.key, dictionary.value
上面的代碼你執(zhí)行兩遍就會報錯,為什么。。。因為插入數(shù)據(jù)庫的主鍵重復(fù)了。。。。
這樣就可以整合到之前的controller.py文件中
# -*- coding: utf-8 -*- from utils import wsgi_wrapper from webob import Response from mako.template import Template # 導(dǎo)入公用的 model 模塊 from model import Session, Dictionary @wsgi_wrapper def hello_app(request): session = Session() # 查詢到所有 Dictionary 對象 dictionaries = session.query(Dictionary) # 然后根據(jù) Dictionary 對象的 key、value 屬性把列表轉(zhuǎn)換成一個字典 data = dict([(dictionary.key, dictionary.value) for dictionary in dictionaries]) tmpl = Template(filename='./simple.html', output_encoding='utf-8') content = tmpl.render(name=request.GET['name'], data=data) return Response(body=content)
五、URL分發(fā)控制
給不同的資源設(shè)計不同的 URL, 客戶端請求這個 URL,web應(yīng)用程序再根據(jù)用戶請求的 URL 定位到具體功能并執(zhí)行之。
提供一個干凈的 URL 有很多好處:
1. 可讀性,通過 URL 就可以大概了解其提供什么功能
2. 用戶容易記住也方便直接輸入
3.設(shè)計良好的 URL 一般都更短小精悍,對搜索引擎也 更友好
使用selector模塊來處理url映射
下載地址http://pypi.python.org/pypi/selector, 下載那個source文件進(jìn)行python setup.py install
首先把urls的配置單獨放到urls.py中
# -*- coding: utf-8 -*- from controller import hello_app mappings = [('/hello/{name}', {'GET':hello_app})]
修改main.py
# -*- coding: utf-8 -*- from wsgiref import simple_server from urls import mappings from selector import Selector # 構(gòu)建 url 分發(fā)器 app = Selector(mappings) server = simple_server.make_server('localhost', 8080, app) server.serve_forever()
然后,在 hello_app 中就可以通過 environ['wsgiorg.routing_args'] 獲取到 name 參數(shù)了,
不過在 wsgi_wrapper 其實還可以進(jìn)一步簡化 hello_app 的工作: 直接把解析得到的參數(shù)
當(dāng)作函數(shù)參數(shù)傳過去!修改 utils.py:
from webob import Request def wsgi_wrapper(func): def new_func(environ, start_response): request = Request(environ) position_args, keyword_args = environ.get('wsgiorg.routing_args', ((), {})) response = func(request, *position_args, **keyword_args) return response(environ, start_response) new_func.__name__ = func.__name__ new_func.__doc__ = func.__doc__ return new_func
那 hello_app 就可以改成這樣了:
... @wsgi_wrapper def hello_app(request, name=''): ... content = tmpl.render(name=name, data=data) return Response(body=content) 執(zhí)行main.py,訪問http://localhost:8080/hello/Python
總結(jié)
以上部分的實現(xiàn),就是類似Django框架中的幾個主要的功能模塊,希望對大家的學(xué)習(xí)有所幫助。
- Python的Django框架中forms表單類的使用方法詳解
- Python的Django框架中消息通知的計數(shù)器實現(xiàn)教程
- Python的Django中將文件上傳至七牛云存儲的代碼分享
- Python的Django框架中使用SQLAlchemy操作數(shù)據(jù)庫的教程
- python+Django+apache的配置方法詳解
- Python的Django應(yīng)用程序解決AJAX跨域訪問問題的方法
- python采用django框架實現(xiàn)支付寶即時到帳接口
- 對Python的Django框架中的項目進(jìn)行單元測試的方法
- python Django模板的使用方法
- 在Python中的Django框架中進(jìn)行字符串翻譯
- Python的Django框架中模板碎片緩存簡介
- 通過mod_python配置運行在Apache上的Django框架
- 在Python的Django框架中顯示對象子集的方法
- 詳解在Python的Django框架中創(chuàng)建模板庫的方法
- 簡單介紹Python的Django框架加載模版的方式
- 在Python的Django框架中包裝視圖函數(shù)
- Python的Django框架下管理站點的基本方法
- 搭建Python的Django框架環(huán)境并建立和運行第一個App的教程
相關(guān)文章
使用卷積神經(jīng)網(wǎng)絡(luò)(CNN)做人臉識別的示例代碼
這篇文章主要介紹了使用卷積神經(jīng)網(wǎng)絡(luò)(CNN)做人臉識別的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Python關(guān)于抽獎系統(tǒng)的思考與設(shè)計思路
這篇文章主要介紹了Python關(guān)于抽獎系統(tǒng)的思考與設(shè)計思路,本文通過一些簡單的例子來說一說抽獎系統(tǒng)背后的邏輯,看看究竟是你運氣不好還是系統(tǒng)邏輯在作怪,需要的朋友可以參考下2023-03-03