drf入門規範
一. Web應用模式#
在開發Web應用中,有兩種應用模式:
知識儲備: 什麼是動態頁面(查資料庫的),什麼是靜態頁面(靜止的html)
Copy# 判斷條件: 根據html頁面內容是寫死的還是從後端動態獲取的
靜態網頁: 頁面上的資料是直接寫死的 萬年不變
動態網頁: 資料是實時獲取的. 如下例子:
1.後端獲取當前時間展示到html頁面上
2.資料是從資料庫中獲取的展示到html頁面上
# 總結
靜: 頁面資料寫死的
動: 查資料庫
1. 前後端不分離#
前後端混合開發(前後端不分離):返回的是html的內容,需要寫模板
關鍵: 請求動態頁面, 返回HTML
2. 前後端分離#
前後端分離:只專注於寫後端介面,返回json,xml格式資料
關鍵: 到靜態檔案伺服器請求靜態頁面, 靜態檔案伺服器返回靜態頁面. 然後JS請求Django後端, Django後端返回json或者XMl格式的資料
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介面#
為了在團隊內部形成共識、防止個人習慣差異引起的混亂,我們需要找到一種大家都覺得很好的介面實現規範,而且這種規範能夠讓後端寫的介面,用途一目瞭然,減少雙方之間的合作成本。
通過網路,規定了前後臺資訊互動規則的url連結,也就是前後臺資訊互動的媒介
Web API介面和一般的url連結還是有區別的,Web API介面簡單概括有下面四大特點
-
url:長得像返回資料的url連結
-
請求方式:get、post、put、patch、delete
- 採用get方式請求上方介面
-
請求引數:json或xml格式的key-value型別資料
- ak:6E823f587c95f0148c19993539b99295
- region:上海
- query:肯德基
- output:json
-
響應結果:json或xml格式的資料
- 上方請求引數的output引數值決定了響應資料的格式
# xml格式
https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295®ion=%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®ion=%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/下載獲得,然後進行傻瓜式安裝。
- 工作面板
- 簡易的get請求
- 簡易的post請求
- 案例:請求百度地圖介面
四. RESTful API規範#
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連結中的v1、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上傳參的形式傳遞搜尋條件#
Copyhttps://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. 返回結果,針對不同操作,伺服器向用戶返回的結果應該符合以下規範#
CopyGET /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視覺化介面來方便檢視測試介面。
官方文件: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()方法
Copypath('books1/', views.Books.as_view())
檢視中Books類
Copyclass 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方法
Copydef 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方法中使用反射獲取請求的型別去執行對應類中定義的請求的方法
Copydef 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中定義的進行判斷
Copyclass View(object):
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
...
2. 圖示分析#
第一步: 專案啟動: views.Books.as_view()就是View類中的view函式記憶體地址
第二步: 路由匹配: 將view加括號呼叫, 並傳入request物件.
第三步: 執行view, 將Books類進行例項化, 例項化出Books類的物件. 這裡的self就是Books類例項化出的物件, 執行self.dispatch方法. self就是Books類例項化出的物件, 如果子類以及物件中都沒有定義, 就會執行View類中的dispatch方法, dispatch方法中就是通過使用者當前的請求的小寫字串進行反射. 當繼承View的類中有get方法, 就會參照物件屬性查詢順序就會呼叫子類中定義的get方法.
3. 流程總結#
Copy1. 專案啟動: 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
即可.
第二步: drf提供的三段認證元件. 執行完request包裝以後執行了三段認證self.initial(…).
第三步: 執行BookAPiView類中定義的方法
第四步: **response沒有立即做了處理, 而是判斷返回的渲染模式. ** 舉例: 如果是postman訪問, 那麼就返回的是json格式. 如果是瀏覽器就會返回好看的頁面, 這個好看的頁面可以根據不同的請求方式對應對資料的操作方法.
三段請求認證元件: self.initial(…)
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檢視的類中含有的方法分析:
2. 流程總結#
Copy1. 專案啟動時: views.BooksAPIView.as_view()等於View中定義as_view方法中view函式. 只不過是通過APIView派生賦值了一些屬性以後返回的
2. 路由匹配時: 在執行檢視類中定義的方法之前. 先將request進行的包裝, 在執行了三段認證組元件, 最後才是執行了檢視類中定義的不同請求的方法
3. 檢視返回時: 先對返回的response進行了處理. 再返回的渲染結果 或者 json格式資料
十. 拓展#
1. 一切皆物件, 函式也是物件#
Copydef 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)),