Django框架深刻了解_01(Django請求生命週期、開發模式、cbv源碼分析、restful規範、跨域、drf的安裝及源碼初識)

1、Django請求生命週期:

前端發出請求到後端,經過Django處理、響應返回給前端相關結果的過程html

先進入實現了wsgi協議的web服務器--->進入django中間件--->路由f分發--->視圖(CBV或FBV)---->取模板,取數據,用數據渲染模板--->返回模板的字符串---->前端頁面獲得數據展示頁面給用戶前端

2、WEB開發模式:

在開發Web應用中,有兩種應用模式:web

先後端不分離
先後端分離
1 先後端不分離
在先後端不分離的應用模式中,前端頁面看到的效果都是由後端控制,由後端渲染頁面或重定向,也就是後端須要控制前端的展現,前端與後端的耦合度很高。ajax

這種應用模式比較適合純網頁應用,可是當後端對接App時,App可能並不須要後端返回一個HTML網頁,而僅僅是數據自己,因此後端本來返回網頁的接口再也不適用於前端App應用,爲了對接App後端還需再開發一套接口。django

2 先後端分離
在先後端分離的應用模式中,後端僅返回前端所需的數據,再也不渲染HTML頁面,再也不控制前端的效果。至於前端用戶看到什麼效果,從後端請求的數據如何加載到前端中,都由前端本身決定,網頁有網頁的處理方式,App有App的處理方式,但不管哪一種前端,所需的數據基本相同,後端僅需開發一套邏輯對外提供數據便可。json

在先後端分離的應用模式中 ,前端與後端的耦合度相對較低。後端

在先後端分離的應用模式中,咱們一般將後端開發的每一個視圖都稱爲一個接口,或者API,前端經過訪問接口來對數據進行增刪改查。api

3、cbv源碼分析:

cbv--基於類的視圖,一開始咱們寫視圖層的時候是基於函數來處理前端請求數據FBV,這只是一種方法,更經常使用的還有在視圖層使用類的方法來創建視圖層跨域

cbv流程:數組

建立路由

url(r'^test/', views.Test.as_view()),

--->建立類的視圖

class Test(View):
    def get(self,request):
        return HttpResponse('cbv_get')
    
    def post(self,request):
        return HttpResponse('cbv_post')

前端請求經過中間件進入路由--->根據路由匹配,成功後會執行後面的Test.as_view()函數,而as_view()在Django啓動的時候就會自動執行返回一個view的函數內存地址,此時路由匹配成功就會view加括號執行該函數,而view內部又調用了self.dispatch函數方法,dispatch會根據請求的方式不一樣,執行咱們定義的類中對應請求名稱的函數方法(好比get請求,就會執行類中get的函數方法)

4、認識RESTful

即Representational State Transfer的縮寫。維基百科稱其爲「具象狀態傳輸」,國內大部分人理解爲「表現層狀態轉化」。

RESTful是一種開發理念。維基百科說:REST是設計風格而不是標準。 REST描述的是在網絡中client和server的一種交互形式;REST自己不實用,實用的是如何設計 RESTful API(REST風格的網絡接口),一種萬維網軟件架構風格。

咱們先來具體看下RESTful風格的url,好比我要查詢商品信息,那麼

非REST的url:http://.../queryGoods?id=1001&type=t01

REST的url: http://.../t01/goods/1001

能夠看出REST特色:url簡潔,將參數經過url傳到服務器,而傳統的url比較囉嗦,並且現實中瀏覽器地址欄會拼接一大串字符,想必大家都見過吧。可是採用REST的風格就會好不少,如今不少的網站已經採用這種風格了,這也是潮流方向,典型的就是url的短化轉換。

那麼,到底什麼是RESTFul架構: 若是一個架構符合REST原則,就稱它爲RESTful架構。

要理解RESTful架構,理解Representational State Transfer這三個單詞的意思。

具象的,就是指表現層,要表現的對象也就是「資源」,什麼是資源呢?網站就是資源共享的東西,客戶端(瀏覽器)訪問web服務器,所獲取的就叫資源。好比html,txt,json,圖片,視頻等等。

表現,好比,文本能夠用txt格式表現,也能夠用HTML格式、XML格式、JSON格式表現,甚至能夠採用二進制格式;圖片能夠用JPG格式表現,也能夠用PNG格式表現。

瀏覽器經過URL肯定一個資源,可是如何肯定它的具體表現形式呢?應該在HTTP請求的頭信息中用Accept和Content-Type字段指定,這兩個字段纔是對"表現層"的描述。

狀態轉換, 就是客戶端和服務器互動的一個過程,在這個過程當中, 勢必涉及到數據和狀態的變化, 這種變化叫作狀態轉換。

互聯網通訊協議HTTP協議,客戶端訪問必然使用HTTP協議,若是客戶端想要操做服務器,必須經過某種手段,讓服務器端發生"狀態轉化"(State Transfer)。

HTTP協議實際上含有4個表示操做方式的動詞,分別是 GET,POST,PUT,DELETE,他們分別對應四種操做。GET用於獲取資源,POST用於新建資源,PUT用於更新資源,DElETE用於刪除資源。GET和POST是表單提交的兩種基本方式,比較常見,而PUT和DElETE不太經常使用。

並且HTTP協議是一種無狀態協議,這樣就必須把全部的狀態都保存在服務器端。所以,若是客戶端想要操做服務器,必須經過某種手段,讓服務器端發生"狀態轉化"(State Transfer)

總結
綜合上面的解釋,RESTful架構就是:

每個URL表明一種資源;
客戶端和服務器之間,傳遞這種資源的某種表現層;
客戶端經過四個HTTP動詞,對服務器端資源進行操做,實現"表現層狀態轉化"。

RESTful規範

  • API與用戶的通訊協議,老是使用HTTPs協議
  • 域名 
    • https://api.example.com                         儘可能將API部署在專用域名(會存在跨域問題)
    • https://example.org/api/                         API很簡單
  • 版本
    • URL,如:https://api.example.com/v1/
    • 請求頭                                                  跨域時,引起發送屢次請求
  • 路徑,視圖網絡上任何東西都是資源,均使用名詞表示(可複數)
    • https://api.example.com/v1/zoos
    • https://api.example.com/v1/animals
    • https://api.example.com/v1/employees
  • method,經過請求方式method 區分是什麼操做
    • GET      :從服務器取出資源(一項或多項)
    • POST    :在服務器新建一個資源
    • PUT/PATCH   :在服務器更新資源
    • DELETE :從服務器刪除資源
  • 過濾,經過在url上傳參的形式傳遞搜索條件
    • https://api.example.com/v1/zoos?limit=10:指定返回記錄的數量
    • https://api.example.com/v1/zoos?offset=10:指定返回記錄的開始位置
    • https://api.example.com/v1/zoos?page=2&per_page=100:指定第幾頁,以及每頁的記錄數
    • https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回結果按照哪一個屬性排序,以及排序順序
    • https://api.example.com/v1/zoos?animal_type_id=1:指定篩選條件
  • 狀態碼
    200 OK - [GET]:服務器成功返回用戶請求的數據,該操做是冪等的(Idempotent)。
    201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數據成功。
    202 Accepted - [*]:表示一個請求已經進入後臺排隊(異步任務)
    204 NO CONTENT - [DELETE]:用戶刪除數據成功。
    400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發出的請求有錯誤,服務器沒有進行新建或修改數據的操做,該操做是冪等的。
    401 Unauthorized - [*]:表示用戶沒有權限(令牌、用戶名、密碼錯誤)。
    403 Forbidden - [*] 表示用戶獲得受權(與401錯誤相對),可是訪問是被禁止的。
    404 NOT FOUND - [*]:用戶發出的請求針對的是不存在的記錄,服務器沒有進行操做,該操做是冪等的。
    406 Not Acceptable - [GET]:用戶請求的格式不可得(好比用戶請求JSON格式,可是隻有XML格式)。
    410 Gone -[GET]:用戶請求的資源被永久刪除,且不會再獲得的。
    422 Unprocesable entity - [POST/PUT/PATCH] 當建立一個對象時,發生一個驗證錯誤。
    500 INTERNAL SERVER ERROR - [*]:服務器發生錯誤,用戶將沒法判斷髮出的請求是否成功。
    
    更多看這裏:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
  • 錯誤處理,應返回錯誤信息,error當作key。
    {
        error: "Invalid API key"
    }
  • 返回結果,針對不一樣操做,服務器向用戶返回的結果應該符合如下規範。
    GET /collection:返回資源對象的列表(數組)
    GET /collection/resource:返回單個資源對象
    POST /collection:返回新生成的資源對象
    PUT /collection/resource:返回完整的資源對象
    PATCH /collection/resource:返回完整的資源對象
    DELETE /collection/resource:返回一個空文檔
  • Hypermedia API,RESTful API最好作到Hypermedia,即返回結果中提供連接,連向其餘API方法,使得用戶不查文檔,也知道下一步應該作什麼。
    {"link": {
      "rel":   "collection https://www.example.com/zoos",
      "href":  "https://api.example.com/zoos",
      "title": "List of zoos",
      "type":  "application/vnd.yourformat+json"
    }}

 補充知識:跨域

瀏覽器的同源策略限制了從同一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的重要安全機制。」

簡單來講就是:比如在一個瀏覽器上訪問兩個不一樣的網站,這兩個網站頁面有本身的腳本,他們在訪問請求服務器資源時,瀏覽器會檢查它們屬於哪一個網站或者說服務器,若是它跨服務器訪問了,那麼瀏覽器就拒絕這種請求

瀏覽器安全的基石是 同源策略,什麼是同源策略呢?言簡意賅,就是三個相同:

協議相同。
域名相同。
端口相同。
這三者相同的狀況下,才被稱做 「同源」,同源策略,能夠保證你的服務器的接口是隱私的。

跨域的例子:

端口不一樣:

假設,你的電腦如今有開啓了兩個服務器,分別在 不一樣的端口

http://localhost:8080/index.html    // 發送 ajax 請求

http://localhost:3000    //         提供接口

在這裏,這個服務器並無遵照 同源策略 了,此時,就產生了跨域問題。

協議不一樣:

舉一個很常見的例子,雙擊打開一個 html 文件,你會看到

file:///Users/xxx/Documents/index.html    // 客戶端
同時在瀏覽器上你會看到: http://localhost:3000 // 服務器

這就是簡單的 協議不一樣 的跨域例子,這個例子,也是咱們最好實現的例子 。。。

域名不一樣:

這個更明顯了:

https://www.xxx.com/index.html    // 客戶端

https://www.yyy.com        // 服務器

解決方案

1.安裝django-cors-headers

pip3 install django-cors-headers

2.配置settings.py文件

INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
 ] 

MIDDLEWARE_CLASSES = (
    ...
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware', # 注意順序
    ...
)
#跨域增長忽略
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = (
    '*'
)

CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
    'VIEW',
)

CORS_ALLOW_HEADERS = (
    'XMLHttpRequest',
    'X_FILENAME',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
    'Pragma',
)

其餘解決方案

1.使用JSONP

使用Ajax獲取json數據時,存在跨域的限制。不過,在Web頁面上調用js的script腳本文件時卻不受跨域的影響,JSONP就是利用這個來實現跨域的傳輸。所以,咱們須要將Ajax調用中的dataType從JSON改成JSONP(相應的API也須要支持JSONP)格式。 
JSONP只能用於GET請求。

2.直接修改Django中的views.py文件

修改views.py中對應API的實現函數,容許其餘域經過Ajax請求數據: 

def myview(_request): 
response = HttpResponse(json.dumps({「key」: 「value」, 「key2」: 「value」})) 
response[「Access-Control-Allow-Origin」] = 「*」 
response[「Access-Control-Allow-Methods」] = 「POST, GET, OPTIONS」 
response[「Access-Control-Max-Age」] = 「1000」 
response[「Access-Control-Allow-Headers」] = 「*return response

5、基於原生django開發restful的接口

def books(request):
    # 獲取全部圖書
    if request.method=='GET':
        books=models.Book.objects.all()
        #把queryset對象轉成json格式字符串
        # ll=[]
        # for book in books:
        #     bo={'name':book.name,'publish':book.publish}
        #     ll.append(bo)
        #列表推導式
        ll=[{'name':book.name,'publish':book.publish} for book in books]
        response={'code':100,'msg':'查詢成功','data':ll}
        #safe=False 若是序列化的對象中有列表,須要設置
        return JsonResponse(response,safe=False,json_dumps_params={'ensure_ascii':False})

 6、drf安裝、使用、APIView 的源碼、equset的源碼分析

DRF:Django REST framework

Django REST framework 框架是一個用於構建Web API 的強大而又靈活的工具。

一般簡稱爲DRF框架 或 REST framework。

DRF框架是創建在Django框架基礎之上,由Tom Christie大牛二次開發的開源項目。

特色

  • 提供了定義序列化器Serializer的方法,能夠快速根據 Django ORM 或者其它庫自動序列化/反序列化;
  • 提供了豐富的類視圖、Mixin擴展類,簡化視圖的編寫;
  • 豐富的定製層級:函數視圖、類視圖、視圖集合到自動生成 API,知足各類須要;
  • 多種身份認證和權限認證方式的支持;
  • 內置了限流系統;
  • 直觀的 API web 界面;
  • 可擴展性,插件豐富

安裝、使用

-pip3 install djangorestframework
-pycharm中安裝
-第一步,再寫視圖,都寫cbv
from rest_framework.views import  APIView
class Books(APIView):
    pass
-在setting中配置 INSTALLED_APPS= [ 。。。。。 'rest_framework' ]

 源碼分析:

APIView

1視圖類繼承了APIView以後,全部的請求都被禁用了csrf認證:
2.在APIView中as_view本質上仍是調用了父類的as_view(View的as_view)

 3.as_view中調用dispatch,這個dispatch是APIView的dispatch

 

 APIView之dispatch方法:

-一、對原生的request對象作了一層包裝(面向對象的封裝),之後再用的request對象都是drf的新的request對象

-二、2 在APIView中self.initial(request, *args, **kwargs),裏面有頻率控制,權限控制和認證相關

-3 根據請求方法執行我們寫的視圖類中的相應方法
--視圖類中方法的request對象,已經變成了封裝後的request

 APIView之Request方法:

-1 原生的request是self._request

-2 取以post形式提交的數據,從request.data中取(urlencoded,formdata,json格式)

-3 query_params 就是原生request的GET的數據

-4 上傳的文件是從FILES中取
-5 (重點)其餘的屬性,直接request.屬性名(由於重寫了__getattr__方法)

 

相關文章
相關標籤/搜索