咱們首先來看django的請求生命週期html
-先進入實現了wsgi協議的web服務器----》進入django---》中間件---》路由---》視圖---》取模板,取數據,用數據渲染模板---》返回模板的字符串---》在瀏覽器上看到頁面了前端
這裏咱們不妨來看看wsgire協議和CGI協議python
CGI是比較原始的開發動態網站的方式。你能夠想象一下,一個網站的動態內容確定是程序生成的,光是靜態的html頁面沒法達到這個效果。那麼,這個程序就須要接受客戶端的請求,而後進行相應處理,再返回給客戶端,客戶端和服務端的通訊固然是經過HTTP協議。而後咱們會發現,這個程序在處理客戶端請求的時候,大部分時候會進行不少重複的工做,好比說HTTP請求的解析。也就是說,你的程序須要解析HTTP請求,個人程序也須要解析。因而爲了DRY原則,Web服務器誕生了。(如下所說的都是CGI的工做模式)web
因而Web服務器能夠解析這個HTTP請求,而後把這個請求的各類參數寫進進程的環境變量,好比REQUEST_METHOD,PATH_INFO之類的。以後呢,服務器會調用相應的程序來處理這個請求,這個程序也就是咱們所要寫的CGI程序了。它會負責生成動態內容,而後返回給服務器,再由服務器轉交給客戶端。服務器和CGI程序之間通訊,通常是經過進程的環境變量和管道。這樣作雖然很清晰,但缺點就是每次有請求,服務器都會fork and exec,每次都會有一個新的進程產生,開銷仍是比較大的。緣由在與CGI程序是一個獨立的程序,它是能夠獨立運行的(在提供HTTP請求的狀況下),它能夠用幾乎全部語言來寫,包括perl,c,lua,python等等。因此對於一個程序,服務器只能以fork and exec的方式來調用它了。django
WSGI是Web Server Gateway Interface的縮寫。以層的角度來看,WSGI所在層的位置低於CGI。但與CGI不一樣的是WSGI具備很強的伸縮性且能運行於多線程或多進程的環境下,這是由於WSGI只是一份標準並無定義如何去實現。實際上WSGI並不是CGI,由於其位於web應用程序與web服務器之間,而web服務器能夠是CGI,mod_python(注:現一般使用mod_wsgi代替),FastCGI或者是一個定義了WSGI標準的web服務器就像python標準庫提供的獨立WSGI服務器稱爲wsgiref。json
WSGI裏的組件分爲『Server』,『Middleware』和『Application』三種,其中的『Middleware』是『設計模式』裏的Decorator(裝飾器)。設計模式
WSGI規範在PEP-333裏講得很詳細:PEP 0333 -- Python Web Server Gateway Interface v1.0 ,但我以爲比理解規範更重要的,是理解其設計目的和工做原理。api
WSGI規範寫得有點繞,之因此繞, 主要緣由多是沒有用『類型提示(Type Hints)』,若是用強類型OOP語言的那種『Interface』和『UML』來解釋會清晰不少。瀏覽器
實現了wsgi 協議對應的web服務器就是uwsgi,相似Java中的tomcat 。有興趣的話能夠讀一下tomcat原理https://blog.csdn.net/qq_38977097/article/details/81089172tomcat
CBV 源碼分析
原生django的視圖層能夠分爲兩類 FBV和CBV,因爲djangorestframework只可以由FBV完成,因此簡單來看一下FBV的源碼。
在FBV視圖裏面 ,咱們的路由是類加as_view(),可是咱們寫的類並無這個屬性或方法 ,實際上是用了父類(view)的
as_view的方法,
不難看出這就是一個閉包函數,傳參給view函數,這時候會走view裏面的self.dispatch方法,因爲對象沒有,只可以走父類(view)的dispatch方法
dispatch方法只是利用了反射請求方法來分發函數,至此咱們對CBV源碼有了一個簡單認識。看懂這個將對咱們理解後面的drf有極大地幫助。
restful規範
下面咱們逐條來分析一下restful規範的設計
1 API與用戶的通訊協議,老是使用HTTPs協議。
2 域名有區分
-https://api.example.com
-https://example.org/api/
3 版本
能夠放在路徑中
能夠放在請求頭中
4 路徑,視網絡上任何東西都是資源,均使用名詞表示
https://api.example.com/v1/zoos
5 經過method 區分是什麼操做
get表示獲取
post表示新增
delete表示刪除
patch/put 表示修改
6 過濾,經過在url上傳參的形式傳遞搜索條件
7 狀態碼
{"status_code":100}
8 錯誤處理,應返回錯誤信息
{"status_code":100,'msg':'登陸成功'}
{"status_code":101,'msg':'用戶名錯誤'}
9 返回結果,針對不一樣操做,服務器向用戶返回的結果
get獲取全部資源/get獲取一個資源
127.0.0.1/api/vi/books 獲取全部圖書
{"status_code":100,'msg':'獲取成功',data:[{},{}]}
127.0.0.1/api/vi/books/3 獲取id爲3的圖書
{"status_code":100,'msg':'獲取成功',data:{name:xx,....}}
新增數據,把新增的數據再返回
修改了數據,返回完整的資源對象
刪除數據,返回一個空文檔
10 返回結果中提供連接
{"link": {
"rel": "collection https://www.example.com/zoos",
"href": "https://api.example.com/zoos",
"title": "List of zoos",
"type": "application/vnd.yourformat+json"
}}
基於原生django開發restful的接口
from django.views import View from app01 import models class APIView(View): def dispatch(self, request, *args, **kwargs): #寫一些頻率控制的東西 ret = super().dispatch(request, *args, **kwargs) return ret class Test(APIView): # http_method_names=['get'] def get(self,request, *args, **kwargs): return HttpResponse('ok')
djangorestframework
安裝下載:pip install djangorestframework
from rest_framework.views import APIView class Books(APIView): def get(self,request): #request是被封裝後的request,原生的request在request._request #若是想用原生requset中的屬性,仍是原來的用法,由於Request重寫了__getattr__方法 # 原生django只能處理urlencoded和formdata編碼,若是是json格式,原生django是不能處理的,須要本身從body中取出來自行處理 # request.data 無論前端傳數據的編碼格式是urlencoded,formdata或者是json,都從裏面取值 # request.data #request.query_params 是原來django原生的GET中的數據 #self.FILES 就是上傳的文件 dic={'name':'lqz','age':30,'height':178,'wife':['liuyifei','dilireba','egon']} return JsonResponse(dic)
#在settings.py文件中添加rest_framework,這就是django的一個app。
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', 'rest_framework' ]
咱們對drf的源碼分析,首先咱們定義一個類,這個類繼承的事APIView
繼承了APIView 以後:
1 全部的請求都沒有csrf的認證了
2 在APIView中as_view本質仍是調用了父類的as_view(View的as_view)
3 as_view中調用dispatch -----》這個dispatch是APIView的dispatch
APIVIew的dispatch方法:
1 對原生request對象作了一層包裝(面向對象的封裝),之後再用的request對象都新的request對象
2 在APIView中self.initial(request, *args, **kwargs),裏面有頻率控制,權限控制和認證相關
3 根據請求方法執行我們寫的視圖類中的相應方法
這個時候視圖類中方法的request對象,已經變成了封裝後的request
Request類:
1 原生的request是self._request
2 取以post形式提交的數據,從request.data中取(urlencoded,formdata,json格式)
3 query_params 就是原生request的GET的數據
4 上傳的文件是從FILES中取
5 (重點)其餘的屬性,直接request.屬性名(由於重寫了__getattr__方法)