Django 中的設(shè)計(jì)模式

Django是MVC模式嗎秘案?

首先說(shuō)說(shuō)Web服務(wù)器開(kāi)發(fā)領(lǐng)域里著名的MVC模式生真,所謂MVC就是把Web應(yīng)用分為 模型(M)什燕、控制器(C)和試圖(V)三層卿闹,他們之間以一種插件式的揭糕、松耦合的方式連接在一起,模型負(fù)責(zé)業(yè)務(wù)對(duì)象與數(shù)據(jù)庫(kù)的映射(ORM)锻霎,試圖負(fù)責(zé)與用戶的交互(頁(yè)面)著角,控制器接受用戶的輸入調(diào)用模型和試圖完成用戶的請(qǐng)求。

Django的MTV模式本質(zhì)上和MVC是一樣的量窘,也是為了各自組建保持一個(gè)松耦合關(guān)系雇寇,只是定義上有些許的不同,Django的MTV分別是:
M 代表模型(model):負(fù)責(zé)業(yè)務(wù)對(duì)象和數(shù)據(jù)庫(kù)的關(guān)系映射(ORM)
T 代表模板(Templates) : 負(fù)責(zé)如何把頁(yè)面展示給用戶(HTML)
V 代表試圖(View) :負(fù)責(zé)業(yè)務(wù)邏輯,并在適當(dāng)?shù)臅r(shí)候調(diào)用Model和Template

除了以上三層之外锨侯,還需要一個(gè)URL分離器嫩海,他的作用是將一個(gè)個(gè)URL的頁(yè)面請(qǐng)求分發(fā)給不同的View處理,View在調(diào)用相應(yīng)的Model和Template

1囚痴、Web服務(wù)器(中間件)收到一個(gè)http請(qǐng)求
2叁怪、Django在URLconf里查找相對(duì)應(yīng)的試圖(View)函數(shù)來(lái)處理http請(qǐng)求
3、試圖函數(shù)調(diào)用相應(yīng)的數(shù)據(jù)模型來(lái)存取數(shù)據(jù)深滚、調(diào)用相應(yīng)的模板展示頁(yè)面
4奕谭、試圖函數(shù)處理結(jié)束后返回一個(gè)http的響應(yīng)給Web服務(wù)器
5、Web服務(wù)器將響應(yīng)發(fā)送給客戶端

這種設(shè)計(jì)模式關(guān)鍵的優(yōu)勢(shì)在于各種組件都是的松耦合的痴荐,這樣的話血柳,每個(gè)由Django驅(qū)動(dòng)的Web應(yīng)用都有著明確的目的,并且可以獨(dú)立更改而不影響到其他的部分

比如生兆,開(kāi)發(fā)者更改一個(gè)應(yīng)用程序中的URL难捌,而不用影響這個(gè)程序底層的實(shí)現(xiàn),設(shè)計(jì)師可以改變HTML頁(yè)面的樣式而不用接觸Python代碼

數(shù)據(jù)管理員可以重新命名數(shù)據(jù)庫(kù)鸦难,并且只需要更改模型根吁,無(wú)需從一大堆文件中查找和替換

Django 是如何工作的?

下圖顯示了在Django應(yīng)用中一個(gè)典型的web請(qǐng)求是如何被處理的



前面的圖片展示了一個(gè)從訪客的瀏覽器到Django應(yīng)用并返回的一個(gè)Web請(qǐng)求的簡(jiǎn)單歷程合蔽,如下是數(shù)字標(biāo)識(shí)的路徑:
1击敌、瀏覽器發(fā)送請(qǐng)求(基本上是字節(jié)類型的字符串)到web服務(wù)器
2、Web服務(wù)器(比如拴事,Nginx)把這個(gè)請(qǐng)求轉(zhuǎn)交到一個(gè)WSGI(比如沃斤,uWSGI),或者直接的文件系統(tǒng)能夠取出一個(gè)文件(比如挤聘,一個(gè)CSS文件)轰枝。
3、不像Web服務(wù)器那樣组去,WSGI服務(wù)器可以直接運(yùn)行Python應(yīng)用鞍陨,請(qǐng)求生成一個(gè)被稱為environ的Python字典,而且从隆,可以選擇傳遞過(guò)去幾個(gè)中間件的層诚撵,最終達(dá)到Django應(yīng)用
4、URLconf中含有屬于應(yīng)用的urls.py選擇一個(gè)試圖處理汲取請(qǐng)求的URL的那個(gè)請(qǐng)求键闺,這個(gè)請(qǐng)求就已經(jīng)變成了HttpRequest——一個(gè)Python字典對(duì)象寿烟。
5、被選擇的那個(gè)試圖通常要做下面所列出的一件或多件事情:

  • 通過(guò)模型與數(shù)據(jù)庫(kù)對(duì)話
  • 使用模板渲染HTML或者任何格式化過(guò)的響應(yīng)
  • 返回一個(gè)純文本響應(yīng)(不被顯示的)
  • 拋出一個(gè)異常

6辛燥、HttpResponse對(duì)象離開(kāi)Django后筛武,被渲染為一個(gè)字符串
7缝其、在瀏覽器見(jiàn)到一個(gè)美化的,渲染后的web頁(yè)面徘六。

雖然某些細(xì)節(jié)被省略掉内边,這個(gè)解釋?xiě)?yīng)該有助于欣賞Django的高級(jí)架構(gòu),他也展示了關(guān)鍵的組件所扮演的角色待锈,比如模型漠其,試圖和模板,Django的很多組件都基于這幾個(gè)廣為人知的設(shè)計(jì)模式

命令模式

在軟件系統(tǒng)中竿音,“行為請(qǐng)求者”與“行為實(shí)現(xiàn)者”通常呈現(xiàn)一種“緊耦合”和屎。但在某些場(chǎng)合,比如要對(duì)行為進(jìn)行“記錄春瞬、撤銷/重做柴信、事務(wù)”等處理,這種無(wú)法抵御變化的緊耦合是不合適的快鱼。在這種情況下颠印,如何將“行為請(qǐng)求者”與“行為實(shí)現(xiàn)者”解耦纲岭?將一組行為抽象為對(duì)象抹竹,實(shí)現(xiàn)二者之間的松耦合,這就是命令模式(Command Pattern)止潮。
命令模式有以下特點(diǎn):
1窃判、命令模式的本質(zhì)是對(duì)命令進(jìn)行封裝,將發(fā)出命令的責(zé)任和執(zhí)行命令的責(zé)任分割開(kāi)喇闸。
2袄琳、每一個(gè)命令都是一個(gè)操作:請(qǐng)求的一方發(fā)出請(qǐng)求,要求執(zhí)行一個(gè)操作燃乍;接收的一方收到請(qǐng)求唆樊,并執(zhí)行操作。
3刻蟹、命令模式允許請(qǐng)求的一方和接收的一方獨(dú)立開(kāi)來(lái)逗旁,使得請(qǐng)求的一方不必知道接收請(qǐng)求的一方的接口,更不必知道請(qǐng)求是怎么被接收舆瘪,以及操作是否被執(zhí)行片效、何時(shí)被執(zhí)行,以及是怎么被執(zhí)行的英古。
4淀衣、命令模式使請(qǐng)求本身成為一個(gè)對(duì)象,這個(gè)對(duì)象和其他對(duì)象一樣可以被存儲(chǔ)和傳遞召调。
5膨桥、命令模式的關(guān)鍵在于引入了抽象命令接口蛮浑,且發(fā)送者針對(duì)抽象命令接口編程,只有實(shí)現(xiàn)了抽象命令接口的具體命令才能與接收者相關(guān)聯(lián)只嚣。

在Django中陵吸,把get和post這些請(qǐng)求的行為抽象成一個(gè)HttpRequest類,我們可以通過(guò)request實(shí)例的method獲取行為的類型:

if request.method == 'GET': 
  do_something()
elif request.method == 'POST': 
  do_something_else()

Django把返回的行為抽象成HttpResponse類介牙,通過(guò)調(diào)用HttpResponse的方法

from django.http import HttpResponse
>>> response = HttpResponse("Here's the text of the Web page.")
>>> response = HttpResponse("Text only, please.", content_type="text/plain")

此外壮虫,對(duì)于不同的數(shù)據(jù),Django還分別抽象了相應(yīng)的類來(lái)處理环础。
Json數(shù)據(jù):

from django.http import JsonResponse
>>> response = JsonResponse({'foo': 'bar'})
>>> response.contentb'{"foo": "bar"}'

File數(shù)據(jù):

from django.http import FileResponse
>>> response = FileResponse(open('myfile.png', 'rb'))
觀察者模式

觀察者模式(有時(shí)又被稱為發(fā)布(publish)-訂閱(Subscribe)模式囚似、模型-視圖(View)模式、源-收聽(tīng)者(Listener)模式或從屬者模式)是軟件設(shè)計(jì)模式的一種线得。在此種模式中饶唤,一個(gè)目標(biāo)物件管理所有相依于它的觀察者物件,并且在它本身的狀態(tài)改變時(shí)主動(dòng)發(fā)出通知贯钩。這通常透過(guò)呼叫各觀察者所提供的方法來(lái)實(shí)現(xiàn)募狂。此種模式通常被用來(lái)實(shí)現(xiàn)事件處理系統(tǒng)。

Django中角雷,存在Singal與dispatch類祸穷,分別用來(lái)發(fā)送和接受信號(hào),實(shí)現(xiàn)被觀察與觀察者的角色勺三。

首先雷滚,我們可以定義一個(gè)觀察者,接收一種特定的信號(hào):

import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

然后我們可以發(fā)送信號(hào)吗坚,使觀察者接收相應(yīng)的信息:

class PizzaStore(object):
  ... 
  def send_pizza(self, toppings, size): 
    pizza_done.send(sender=self.__class__, toppings=toppings, size=size) 
  ...

此外祈远,Django中也有很多built in的signal類,實(shí)現(xiàn)不同的功能商源。

Django RestframWork中的REST設(shè)計(jì)

在使用Django框架的時(shí)候充甚,也許有些追求ROA的碼農(nóng)們可能會(huì)吐槽沒(méi)有REST化支持。在Django Restframework框架中的APIView類中霸褒,提供了put(), delete(), patch()方法的支持伴找。
比如,如果你想上傳一個(gè)文件废菱,對(duì)應(yīng)的view就可以這樣寫(xiě):

class FileUploadView(views.APIView):
  parser_classes = (FileUploadParser,) 

  def put(self, request, filename, format=None): 
    file_obj = request.data['file'] 
    # ... 
    # do some stuff with uploaded file 
    # ... 
    return Response(status=204)

此外技矮,如果你想再服務(wù)器端發(fā)送請(qǐng)求抖誉,Django Restframework中APIClient類提供了各種方法,get(), post(), put(), patch(), delete(), head() and options()衰倦。

from rest_framework.test import APIClient

client = APIClient()
client.post('/notes/', {'title': 'new idea'}, format='json')

總的來(lái)說(shuō)袒炉,Django提供的框架使得代碼量減少了很多,使得程序員只需關(guān)注核心的業(yè)務(wù)邏輯樊零。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末我磁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子驻襟,更是在濱河造成了極大的恐慌夺艰,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,002評(píng)論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沉衣,死亡現(xiàn)場(chǎng)離奇詭異郁副,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)豌习,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門(mén)存谎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人肥隆,你說(shuō)我怎么就攤上這事既荚。” “怎么了巷屿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,787評(píng)論 0 365
  • 文/不壞的土叔 我叫張陵固以,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我嘱巾,道長(zhǎng),這世上最難降的妖魔是什么诫钓? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,237評(píng)論 1 300
  • 正文 為了忘掉前任旬昭,我火速辦了婚禮,結(jié)果婚禮上菌湃,老公的妹妹穿的比我還像新娘问拘。我一直安慰自己,他們只是感情好惧所,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,237評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布骤坐。 她就那樣靜靜地躺著,像睡著了一般下愈。 火紅的嫁衣襯著肌膚如雪纽绍。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,821評(píng)論 1 314
  • 那天势似,我揣著相機(jī)與錄音拌夏,去河邊找鬼僧著。 笑死,一個(gè)胖子當(dāng)著我的面吹牛障簿,可吹牛的內(nèi)容都是我干的盹愚。 我是一名探鬼主播,決...
    沈念sama閱讀 41,236評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼站故,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼皆怕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起西篓,我...
    開(kāi)封第一講書(shū)人閱讀 40,196評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤端逼,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后污淋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體顶滩,經(jīng)...
    沈念sama閱讀 46,716評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,794評(píng)論 3 343
  • 正文 我和宋清朗相戀三年寸爆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了礁鲁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,928評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赁豆,死狀恐怖仅醇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情魔种,我是刑警寧澤析二,帶...
    沈念sama閱讀 36,583評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站节预,受9級(jí)特大地震影響叶摄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜安拟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,264評(píng)論 3 336
  • 文/蒙蒙 一蛤吓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧糠赦,春花似錦会傲、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,755評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至顾瞻,卻和暖如春泼疑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背朋其。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,869評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工王浴, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脆炎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,378評(píng)論 3 379
  • 正文 我出身青樓氓辣,卻偏偏與公主長(zhǎng)得像秒裕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钞啸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,937評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容