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.db.models.signals.pre_save & django.db.models.signals.post_save
當(dāng)一個(gè)model執(zhí)行save()方法车份,即在model對(duì)應(yīng)的數(shù)據(jù)庫(kù)中的一張表插入一條數(shù)據(jù)的前后發(fā)送信號(hào)。django.db.models.signals.pre_delete & django.db.models.signals.post_delete
當(dāng)一個(gè)model執(zhí)行delete()方法牡彻,即在model對(duì)應(yīng)的數(shù)據(jù)庫(kù)中的一張表刪除一條數(shù)據(jù)的前后發(fā)送信號(hào)扫沼。django.db.models.signals.m2m_changed
當(dāng)model中的一個(gè)多對(duì)多的關(guān)系發(fā)生改變時(shí)發(fā)送信號(hào)。django.core.signals.request_started & django.core.signals.request_finished
當(dāng)Django開(kāi)始或者完成一個(gè)HTTP請(qǐng)求的時(shí)候發(fā)送信號(hào)讨便。
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ù)邏輯樊零。