drf入門規範

一. Web應用模式#

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

知識儲備: 什麼是動態頁面(查數據庫的),什麼是靜態頁面(靜止的html)html

Copy
# 判斷條件: 根據html頁面內容是寫死的仍是從後端動態獲取的
靜態網頁: 頁面上的數據是直接寫死的 萬年不變
動態網頁: 數據是實時獲取的. 以下例子: 
    1.後端獲取當前時間展現到html頁面上
    2.數據是從數據庫中獲取的展現到html頁面上
    
# 總結
靜: 頁面數據寫死的
動: 查數據庫

1. 先後端不分離#

先後端混合開發(先後端不分離):返回的是html的內容,須要寫模板前端

關鍵: 請求動態頁面, 返回HTMLjava

先後端不分離

2. 先後端分離#

先後端分離:只專一於寫後端接口,返回json,xml格式數據python

關鍵: 到靜態文件服務器請求靜態頁面, 靜態文件服務器返回靜態頁面. 而後JS請求Django後端, Django後端返回json或者XMl格式的數據git

Copy
# xml格式
<xml>
<name>lqz</name>
</xml>

# json格式
{"name":"lqz"}

# asp 動態服務器頁面. jsp Java服務端網頁
# java---> jsp
https://www.pearvideo.com/category_loading.jsp
#php寫的
http://www.aa7a.cn/user.php
# python寫的
http://www.aa7a.cn/user.html
    
# 動靜態頁面存在的主要做用
優化查詢

先後端分離

3. 總結#

Copy
# 動靜態頁面
    靜態: 頁面內容寫死的, 內容都是固定不變的.
    動態: 頁面內容含有須要從數據庫中獲取的.
        
# 先後端不分離
	特色: 請求動態頁面, 返回HTML數據或者重定向
        
# 先後端分離特色
	特色: 
        請求靜態頁面(向靜態服務器), 返回靜態文件
       	請求須要填充的數據, 返回js或者xml格式數據

二. API接口#

爲了在團隊內部造成共識、防止我的習慣差別引發的混亂,咱們須要找到一種你們都以爲很好的接口實現規範,並且這種規範可以讓後端寫的接口,用途一目瞭然,減小雙方之間的合做成本。github

經過網絡,規定了先後臺信息交互規則的url連接,也就是先後臺信息交互的媒介web

Web API接口和通常的url連接仍是有區別的,Web API接口簡單歸納有下面四大特色數據庫

  • url:長得像返回數據的url連接django

  • 請求方式:get、post、put、patch、delete

    • 採用get方式請求上方接口
  • 請求參數:json或xml格式的key-value類型數據

    • ak:6E823f587c95f0148c19993539b99295
    • region:上海
    • query:肯德基
    • output:json
  • 響應結果:json或xml格式的數據

    • 上方請求參數的output參數值決定了響應數據的格式
Copy
# xml格式
https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295&region=%E4%B8%8A%E6%B5%B7&query=%E8%82%AF%E5%BE%B7%E5%9F%BA&output=xml
    
#json格式
https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295&region=%E4%B8%8A%E6%B5%B7&query=%E8%82%AF%E5%BE%B7%E5%9F%BA&output=json
{
    "status":0,
  	"message":"ok",
    "results":[
        {
            "name":"肯德基(羅餐廳)",
            "location":{
                "lat":31.415354,
                "lng":121.357339
            },
            "address":"月羅路2380號",
            "province":"上海市",
            "city":"上海市",
            "area":"寶山區",
            "street_id":"339ed41ae1d6dc320a5cb37c",
            "telephone":"(021)56761006",
            "detail":1,
            "uid":"339ed41ae1d6dc320a5cb37c"
        }
      	...
		]
}

總結#

Copy
什麼是API接口?
	API接口就是先後端信息交互的媒介(提示: 表示的是先後端之間)

三. 接口測試工具:Postman#

Postman是一款接口調試工具,是一款免費的可視化軟件,同時支持各類操做系統平臺,是測試接口的首選工具。

Postman能夠直接從官網:https://www.getpostman.com/downloads/下載得到,而後進行傻瓜式安裝。

  • 工做面板

img

  • 簡易的get請求

img

  • 簡易的post請求

img

  • 案例:請求百度地圖接口

img

四. RESTful API規範#

restful

REST全稱是Representational State Transfer,中文意思是表述(編者注:一般譯爲表徵性狀態轉移)。 它首次出如今2000年Roy Fielding的博士論文中。

RESTful是一種定義Web API接口的設計風格,尤爲適用於先後端分離的應用模式中。

這種風格的理念認爲後端開發任務就是提供數據的,對外提供的是數據資源的訪問接口,因此在定義接口時,客戶端訪問的URL路徑就表示這種要操做的數據資源。

事實上,咱們可使用任何一個框架均可以實現符合restful規範的API接口。

1. 數據的安全保障#

Copy
# url連接通常都採用https協議進行傳輸

# 注:採用https協議,能夠提升數據交互過程當中的安全性

2. 接口特徵表現#

Copy
# 用api關鍵字標識接口url:
	[https://api.baidu.com](https://api.baidu.com/)
	https://www.baidu.com/api
       
# 注:看到api字眼,就表明該請求url連接是完成先後臺數據交互的

3. 多數據版本共存#

Copy
# 在url連接中標識數據版本
	https://api.baidu.com/v1
	https://api.baidu.com/v2

# 注:url連接中的v一、v2就是不一樣數據版本的體現(只有在一種數據資源有多版本狀況下)

4. 數據便是資源,均使用名詞(可複數)#

Copy
# 接口通常都是完成先後臺數據的交互,交互的數據咱們稱之爲資源
	https://api.baidu.com/users
	https://api.baidu.com/books
	https://api.baidu.com/book

# 注:不要出現操做資源的動詞,錯誤示範:https://api.baidu.com/delete-user

# 例外: 特殊的接口能夠出現動詞,由於這些接口通常沒有一個明確的資源,或是動詞就是接口的核心含義
	https://api.baidu.com/place/search
	https://api.baidu.com/login

5. 資源操做由請求方式決定(method)#

Copy
# 操做資源通常都會涉及到增刪改查,咱們提供請求方式來標識增刪改查動做
    https://api.baidu.com/books   - get請求:   獲取全部書
    https://api.baidu.com/books/1 - get請求:   獲取主鍵爲1的書
    https://api.baidu.com/books   - post請求:  新增一本書
    https://api.baidu.com/books/1 - put請求:   總體修改主鍵爲1的書
    https://api.baidu.com/books/1 - patch請求: 局部修改主鍵爲1的書
    https://api.baidu.com/books/1 - delete請求:刪除主鍵爲1的書

6. 過濾,經過在url上傳參的形式傳遞搜索條件#

Copy
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        指定篩選條件

7. 響應狀態碼#

Copy
# 正常響應
    響應狀態碼2xx
    200:常規請求
    201:建立成功

# 重定向響應
	響應狀態碼3xx
    301:永久重定向
    302:暫時重定向

# 客戶端異常
    響應狀態碼4xx
    403:請求無權限
    404:請求路徑不存在
    405:請求方法不存在

# 服務器異常
    響應狀態碼5xx
    500:服務器異常

8. 錯誤處理,應返回錯誤信息,error當作key#

Copy
{
    error: "無權限操做"
}

9. 返回結果,針對不一樣操做,服務器向用戶返回的結果應該符合如下規範#

Copy
GET /collection             返回資源對象的列表(數組)  多個[{}],
GET /collection/resource    返回單個資源對象           單個{}
POST /collection            返回新生成的資源對象
PUT /collection/resource    返回完整的資源對象
PATCH /collection/resource  返回完整的資源對象
DELETE /collection/resource 返回一個空文檔

10. 須要url請求的資源須要訪問資源的請求連接#

Copy
# Hypermedia API,RESTful API最好作到Hypermedia,即返回結果中提供連接,連向其餘API方法,使得用戶不查文檔,也知道下一步應該作什麼
{
  	"status": 0,
  	"msg": "ok",
  	"results":[
        {
            "name":"肯德基(羅餐廳)",
            "img": "https://image.baidu.com/kfc/001.png"
        }
      	...
		]
}

比較好的接口返回

Copy
# 響應數據要有狀態碼、狀態信息以及數據自己
{
  	"status": 0,
  	"msg": "ok",
  	"results":[
        {
            "name":"肯德基(羅餐廳)",
            "location":{
                "lat":31.415354,
                "lng":121.357339
            },
            "address":"月羅路2380號",
            "province":"上海市",
            "city":"上海市",
            "area":"寶山區",
            "street_id":"339ed41ae1d6dc320a5cb37c",
            "telephone":"(021)56761006",
            "detail":1,
            "uid":"339ed41ae1d6dc320a5cb37c"
        }
      	...
		]
}

11. 總結#

Copy
# 關鍵字: HTTPS協議, api, 版本, 資源標識, 請求方式, url傳參標識, 響應狀態碼, 錯誤信息, 不一樣的操做返回不一樣的結果, 返回url

1. 傳輸數據用HTTPS協議

2. 接口具備標識性
    https://api.baidu.com
    https://www.baidu.com/api
        
3. 接口具備版本標識性
    https://api.baidu.com/v1
    https://api.baidu.com/v2
        
4. 核心: 接口對資源具備標識性(名詞)
    https://api.baidu.com/books
    https://api.baidu.com/book
        
5. 核心: 經過請求的方式來決定對數據的操做方式
    get獲取, post增長, put總體更新, patch局部更新, delete刪除
    
6. 經過url傳參數的形式傳遞搜索條件
    https://api.baidu.com/books?limit=10
        
7. 響應狀態碼
    200常規請求   201建立成功請求
    301永久重定向 302暫時重定向
    403請求無權限 404請求無路徑   405請求方法不存在
    500服務端異常
    
8. 錯誤信息
    {
        'error': '無權限操做'
    }
    
9. 針對不一樣的操做, 返回不一樣的返回結果
    get     獲取多個[{}], 獲取單個{}
    post    返回新增的
    put     返回修改後全部的內容(包括沒修改的. 所有)
    patch   返回修改後全部的內容(包括沒修改的. 所有)
    delete  返回空文檔
    
10. 基於請求響應事後返回內容中, 能夠帶url地址
    {
        "status": 0,
        "msg": "ok",
        "results":[
            {
                "name":"肯德基(羅餐廳)",
                "img": "https://image.baidu.com/kfc/001.png"
             }
        ...
        ]
    }

五. 序列化#

api接口開發,最核心最多見的一個過程就是序列化,所謂序列化就是把數據轉換格式,序列化能夠分兩個階段:

序列化: 把咱們識別的數據轉換成指定的格式提供給別人。

例如:咱們在django中獲取到的數據默認是模型對象,可是模型對象數據沒法直接提供給前端或別的平臺使用,因此咱們須要把數據進行序列化,變成字符串或者json數據,提供給別人。

反序列化:把別人提供的數據轉換/還原成咱們須要的格式。

例如:前端js提供過來的json數據,對於python而言就是字符串,咱們須要進行反序列化換成模型類對象,這樣咱們才能把數據保存到數據庫中。

六. Django Rest_Framework#

核心思想: 縮減編寫api接口的代碼

Django REST framework是一個創建在Django基礎之上的Web 應用開發框架,能夠快速的開發REST API接口應用。在REST framework中,提供了序列化器Serialzier的定義,能夠幫助咱們簡化序列化與反序列化的過程,不只如此,還提供豐富的類視圖、擴展類、視圖集來簡化視圖的編寫工做。REST framework還提供了認證、權限、限流、過濾、分頁、接口文檔等功能支持。REST framework提供了一個API 的Web可視化界面來方便查看測試接口。

drf_logo

官方文檔:https://www.django-rest-framework.org/

github: https://github.com/encode/django-rest-framework/tree/master

特色#

Copy
提供了定義序列化器Serializer的方法,能夠快速根據 Django ORM 或者其它庫自動序列化/反序列化;

提供了豐富的類視圖、Mixin擴展類,簡化視圖的編寫;

豐富的定製層級:函數視圖、類視圖、視圖集合到自動生成 API,知足各類須要;

多種身份認證和權限認證方式的支持;[jwt]

內置了限流系統;

直觀的 API web 界面;

可擴展性,插件豐富

七. drf的安裝和簡單使用#

Copy
# 安裝:pip install djangorestframework==3.10.3

# 使用
# 1. 在setting.py 的app中註冊
    INSTALLED_APPS = [
    'rest_framework'
    ]
    
# 2. 在models.py中寫表模型
    class Book(models.Model):
        nid=models.AutoField(primary_key=True)
        name=models.CharField(max_length=32)
        price=models.DecimalField(max_digits=5,decimal_places=2)
        author=models.CharField(max_length=32)
        
# 3. 新建一個序列化類
    from rest_framework.serializers import ModelSerializer
    from app01.models import  Book
    class BookModelSerializer(ModelSerializer):
        class Meta:
            model = Book
            fields = "__all__"
            
# 4. 在視圖中寫視圖類
    from rest_framework.viewsets import ModelViewSet
    from .models import Book
    from .ser import BookModelSerializer
    class BooksViewSet(ModelViewSet):
        queryset = Book.objects.all()
        serializer_class = BookModelSerializer
        
# 5. 寫路由關係
    from app01 import views
    from rest_framework.routers import DefaultRouter
    router = DefaultRouter()  # 能夠處理視圖的路由器
    router.register('book', views.BooksViewSet)  # 向路由器中註冊視圖集
      # 將路由器中的因此路由信息追到到django的路由列表中
    urlpatterns = [
        path('admin/', admin.site.urls),
    ]
    #這是什麼意思?兩個列表相加
    # router.urls 列表
    urlpatterns += router.urls
    
# 6. 啓動,在postman中測試便可

八. CBV中對繼承的View源碼分析#

1. 代碼分析#

切入點: urls.py中的.as_view()方法

Copy
path('books1/', views.Books.as_view())

視圖中Books類

Copy
class Books(View):
    # 若是有個需求,只能接受get請求
    http_method_names = ['get', ]

    def get(self, request):
        print(self.request)   # 看: 這裏能夠經過self.request進行獲取到request方法
        return HttpResponse('ok')

項目啓動時執行

Copy
@classonlymethod
def as_view(cls, **initkwargs):
	...

    def view(request, *args, **kwargs):
        ...

    ...
    return view

路由匹配時執行, 將執行的類進行實例化, 經過執行路由匹配中類實例化出的對象就能夠執行到繼承父類View中定義的dispatch方法

Copy
def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs
        return self.dispatch(request, *args, **kwargs)

經過dispatch方法中使用反射獲取請求的類型去執行對應類中定義的請求的方法

Copy
def dispatch(self, request, *args, **kwargs):
    # Try to dispatch to the right method; if a method doesn't exist,
    # defer to the error handler. Also defer to the error handler if the
    # request method isn't on the approved list.
    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)

上面的self.http_method_names判斷, 若是子類中沒有派生那麼就會經過View中定義的進行判斷

Copy
class View(object):
    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    ...

2. 圖示分析#

第一步: 項目啓動: views.Books.as_view()就是View類中的view函數內存地址

image-20200707173129838

第二步: 路由匹配: 將view加括號調用, 並傳入request對象.

image-20200707173205967

第三步: 執行view, 將Books類進行實例化, 實例化出Books類的對象. 這裏的self就是Books類實例化出的對象, 執行self.dispatch方法. self就是Books類實例化出的對象, 若是子類以及對象中都沒有定義, 就會執行View類中的dispatch方法, dispatch方法中就是經過用戶當前的請求的小寫字符串進行反射. 當繼承View的類中有get方法, 就會參照對象屬性查找順序就會調用子類中定義的get方法.

image-20200707181058653

3. 流程總結#

Copy
1. 項目啓動: views.Books.as_view()就是View類中的view函數內存地址
2. 路由匹配: 將view加括號調用, 並傳入request對象. 
3. 執行view: 將Books類進行實例化, 實例化出Books類的對象. 這裏的self就是Books類實例化出的對象
4. 執行self.dispatch方法: self就是Books類實例化出的對象, 若是之類以及對象中都沒有定義, 就會執行View類中的dispatch方法
5. dispatch方法中就是經過用戶當前的請求的小寫字符串進行反射. 當繼承View的類中有get方法, 根據對象屬性查找順序就會調用子類中定義的get方法.

九. CBV中對繼承的APIView源碼分析#

1. 圖示分析#

項目啓動: BooksAPIView就是View類中的view函數的內存地址. 只不過由APIView進行了派生, 再次self.cls=cls等包裝加工之後返回的.

路由匹配加括號調用view(request)執行:

第一步: request包裝. 在執行BooksAPIView中定義的請求方法以前, 先作了request的包裝, BooksAPIView中獲取的request再也不是原生髮過來的request對象了, 若是想要獲取原生的request對象咱們能夠經過self.request._request 或者 request.request便可.

image-20200707181421955

第二步: drf提供的三段認證組件. 執行完request包裝之後執行了三段認證self.initial(…).

image-20200707172828072

第三步: 執行BookAPiView類中定義的方法

第四步: **response沒有當即作了處理, 而是判斷返回的渲染模式. ** 舉例: 若是是postman訪問, 那麼就返回的是json格式. 若是是瀏覽器就會返回好看的頁面, 這個好看的頁面能夠根據不一樣的請求方式對應對數據的操做方法.

5

三段請求認證組件: self.initial(…)

image-20200707064509312

Copy
# APIView的initial方法
 	def initial(self, request, *args, **kwargs):
        # 認證組件:校驗用戶 - 遊客、合法用戶、非法用戶
        # 遊客:表明校驗經過,直接進入下一步校驗(權限校驗)
        # 合法用戶:表明校驗經過,將用戶存儲在request.user中,再進入下一步校驗(權限校驗)
        # 非法用戶:表明校驗失敗,拋出異常,返回403權限異常結果
        self.perform_authentication(request)
        # 權限組件:校驗用戶權限 - 必須登陸、全部用戶、登陸讀寫遊客只讀、自定義用戶角色
        # 認證經過:能夠進入下一步校驗(頻率認證)
        # 認證失敗:拋出異常,返回403權限異常結果
        self.check_permissions(request)
        # 頻率組件:限制視圖接口被訪問的頻率次數 - 限制的條件(IP、id、惟一鍵)、頻率週期時間(s、m、h)、頻率的次數(3/s)
        # 沒有達到限次:正常訪問接口
        # 達到限次:限制時間內不能訪問,限制時間達到後,能夠從新訪問
        self.check_throttles(request)

繼承APIView視圖的類中含有的方法分析:

6

2. 流程總結#

Copy
1. 項目啓動時: views.BooksAPIView.as_view()等於View中定義as_view方法中view函數. 只不過是經過APIView派生賦值了一些屬性之後返回的
2. 路由匹配時: 在執行視圖類中定義的方法以前. 先將request進行的包裝, 在執行了三段認證組組件, 最後纔是執行了視圖類中定義的不一樣請求的方法
3. 視圖返回時: 先對返回的response進行了處理. 再返回的渲染結果 或者 json格式數據

十. 拓展#

1. 一切皆對象, 函數也是對象#

Copy
def foo(a, b):
    return a + b


foo.name = 'lqz'  # 因爲一切皆對象,函數也是個對象,對象放值

print(foo(2, 3))

print(foo.name)  # lqz

2. 局部禁用csrf方法csrf_exempt#

Copy
# 提示: 在視圖函數上加裝飾器@csrf_exempt. 與csrf_exempt(view)這麼寫和在視圖函數上加裝飾器是如出一轍的.

# urls.py中這種寫法本質就是返回的views.test, 只是在原來基礎之上不修改的調用方式, 以及原代碼的狀況下, 去除了csrf認證
path('test/', csrf_exempt(views.test)),
相關文章
相關標籤/搜索