正如我們了解到的,Django 寫(xiě)視圖函數(shù)有兩種寫(xiě)法:cbv 和 fbv疟位。cbv 提倡使用類來(lái)寫(xiě)瞻润,fbv 使用函數(shù)來(lái)寫(xiě)。當(dāng)然為了代碼的重復(fù)行,官方更推薦使用 cbv绍撞。
寫(xiě) cbv 時(shí)正勒,寫(xiě)好 class 類視圖,然后在 url 中調(diào)用 class 的 as_view() 函數(shù)楚午,以前一直以為只要會(huì)調(diào)用即可昭齐,沒(méi)有去理解內(nèi)涵。當(dāng)然 fbv 直接執(zhí)行函數(shù)即可矾柜。今天來(lái)看一看 cbv 方式的源碼阱驾。
在 PyCharm 中進(jìn)入 as_view 的源碼,發(fā)現(xiàn)其是一個(gè) classmethod怪蔑。
# 對(duì)具體代碼省略
def as_view(cls, **initkwargs):
# 是 request-response 過(guò)程主要入口點(diǎn)
...
def view(request, *args, **kwargs):
...
return self.dispatch(request, *args, **kwargs)
...
return view
可以看到內(nèi)部使用呢閉包里覆,返回了 view 函數(shù),而 view 函數(shù)又返回了 dispatch 方法缆瓣。那么繼續(xù)進(jìn)入 dispatch 方法喧枷。
# 這段代碼不長(zhǎng)
def dispatch(self, request, *args, **kwargs):
# 試著找到正確的方法,如果方法不存在弓坞,進(jìn)行錯(cuò)誤處理
# 如果請(qǐng)求方法不在允許列表中隧甚,也進(jìn)行錯(cuò)誤處理程序。
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
可以看到其判斷了 request.method.lower() 是否在一個(gè)列表中渡冻,這個(gè)列表是在 view 中的
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
如果在列表中戚扳,那么取出 self 對(duì)應(yīng)的方法。如果沒(méi)有的話族吻,那么也進(jìn)入異常處理程序帽借。這也就解釋了 cbv 中的函數(shù)命名和 http method 高度重合。注意 getattr 的用法超歌。
這就差不多結(jié)束了砍艾。整理一下:
as_view() --> view() --> dispatch()
這主要是利用了反射原理。url 映射也差不多是這個(gè)原理(猜測(cè))巍举。
總結(jié):請(qǐng)求進(jìn)入 dispatch 方法中脆荷,反射找到類中的 get/post 等方法,然后將對(duì)應(yīng)方法中的返回內(nèi)容返回給 dispatch懊悯,然后 dispatch 再將內(nèi)容返回給請(qǐng)求简烘。
后話:也可以在自定義類中實(shí)現(xiàn) dispatch 方法,然后調(diào)用父類的方法定枷。在這之前或之后可以實(shí)現(xiàn)某些操作。