一. Web應用模式#
在開發Web應用中,有兩種應用模式:php
知識儲備: 什麼是動態頁面(查數據庫的),什麼是靜態頁面(靜止的html)html
# 判斷條件: 根據html頁面內容是寫死的仍是從後端動態獲取的
靜態網頁: 頁面上的數據是直接寫死的 萬年不變
動態網頁: 數據是實時獲取的. 以下例子:
1.後端獲取當前時間展現到html頁面上
2.數據是從數據庫中獲取的展現到html頁面上
# 總結
靜: 頁面數據寫死的
動: 查數據庫
1. 先後端不分離#
先後端混合開發(先後端不分離):返回的是html的內容,須要寫模板前端
關鍵: 請求動態頁面, 返回HTMLjava
2. 先後端分離#
先後端分離:只專一於寫後端接口,返回json,xml格式數據python
關鍵: 到靜態文件服務器請求靜態頁面, 靜態文件服務器返回靜態頁面. 而後JS請求Django後端, Django後端返回json或者XMl格式的數據git
# 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. 總結#
# 動靜態頁面
靜態: 頁面內容寫死的, 內容都是固定不變的.
動態: 頁面內容含有須要從數據庫中獲取的.
# 先後端不分離
特色: 請求動態頁面, 返回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參數值決定了響應數據的格式
# 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"
}
...
]
}
總結#
什麼是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. 數據的安全保障#
# url連接通常都採用https協議進行傳輸
# 注:採用https協議,能夠提升數據交互過程當中的安全性
2. 接口特徵表現#
# 用api關鍵字標識接口url:
[https://api.baidu.com](https://api.baidu.com/)
https://www.baidu.com/api
# 注:看到api字眼,就表明該請求url連接是完成先後臺數據交互的
3. 多數據版本共存#
# 在url連接中標識數據版本
https://api.baidu.com/v1
https://api.baidu.com/v2
# 注:url連接中的v一、v2就是不一樣數據版本的體現(只有在一種數據資源有多版本狀況下)
4. 數據便是資源,均使用名詞(可複數)#
# 接口通常都是完成先後臺數據的交互,交互的數據咱們稱之爲資源
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)#
# 操做資源通常都會涉及到增刪改查,咱們提供請求方式來標識增刪改查動做
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上傳參的形式傳遞搜索條件#
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. 響應狀態碼#
# 正常響應
響應狀態碼2xx
200:常規請求
201:建立成功
# 重定向響應
響應狀態碼3xx
301:永久重定向
302:暫時重定向
# 客戶端異常
響應狀態碼4xx
403:請求無權限
404:請求路徑不存在
405:請求方法不存在
# 服務器異常
響應狀態碼5xx
500:服務器異常
8. 錯誤處理,應返回錯誤信息,error當作key#
{
error: "無權限操做"
}
9. 返回結果,針對不一樣操做,服務器向用戶返回的結果應該符合如下規範#
GET /collection 返回資源對象的列表(數組) 多個[{}], GET /collection/resource 返回單個資源對象 單個{} POST /collection 返回新生成的資源對象 PUT /collection/resource 返回完整的資源對象 PATCH /collection/resource 返回完整的資源對象 DELETE /collection/resource 返回一個空文檔
10. 須要url請求的資源須要訪問資源的請求連接#
# Hypermedia API,RESTful API最好作到Hypermedia,即返回結果中提供連接,連向其餘API方法,使得用戶不查文檔,也知道下一步應該作什麼
{
"status": 0,
"msg": "ok",
"results":[
{
"name":"肯德基(羅餐廳)",
"img": "https://image.baidu.com/kfc/001.png"
}
...
]
}
比較好的接口返回
# 響應數據要有狀態碼、狀態信息以及數據自己
{
"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. 總結#
# 關鍵字: 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
特色#
提供了定義序列化器Serializer的方法,能夠快速根據 Django ORM 或者其它庫自動序列化/反序列化; 提供了豐富的類視圖、Mixin擴展類,簡化視圖的編寫; 豐富的定製層級:函數視圖、類視圖、視圖集合到自動生成 API,知足各類須要; 多種身份認證和權限認證方式的支持;[jwt] 內置了限流系統; 直觀的 API web 界面; 可擴展性,插件豐富
七. drf的安裝和簡單使用#
# 安裝: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()方法
path('books1/', views.Books.as_view())
視圖中Books類
class Books(View):
# 若是有個需求,只能接受get請求
http_method_names = ['get', ]
def get(self, request):
print(self.request) # 看: 這裏能夠經過self.request進行獲取到request方法
return HttpResponse('ok')
項目啓動時執行
@classonlymethod
def as_view(cls, **initkwargs):
...
def view(request, *args, **kwargs):
...
...
return view
路由匹配時執行, 將執行的類進行實例化, 經過執行路由匹配中類實例化出的對象就能夠執行到繼承父類View中定義的dispatch方法
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方法中使用反射獲取請求的類型去執行對應類中定義的請求的方法
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中定義的進行判斷
class 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. 流程總結#
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
便可.
第二步: drf提供的三段認證組件. 執行完request包裝之後執行了三段認證self.initial(…).
第三步: 執行BookAPiView類中定義的方法
第四步: **response沒有當即作了處理, 而是判斷返回的渲染模式. ** 舉例: 若是是postman訪問, 那麼就返回的是json格式. 若是是瀏覽器就會返回好看的頁面, 這個好看的頁面能夠根據不一樣的請求方式對應對數據的操做方法.
三段請求認證組件: self.initial(…)
# 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. 流程總結#
1. 項目啓動時: views.BooksAPIView.as_view()等於View中定義as_view方法中view函數. 只不過是經過APIView派生賦值了一些屬性之後返回的
2. 路由匹配時: 在執行視圖類中定義的方法以前. 先將request進行的包裝, 在執行了三段認證組組件, 最後纔是執行了視圖類中定義的不一樣請求的方法
3. 視圖返回時: 先對返回的response進行了處理. 再返回的渲染結果 或者 json格式數據
十. 拓展#
1. 一切皆對象, 函數也是對象#
def foo(a, b):
return a + b
foo.name = 'lqz' # 因爲一切皆對象,函數也是個對象,對象放值
print(foo(2, 3))
print(foo.name) # lqz
2. 局部禁用csrf方法csrf_exempt#
# 提示: 在視圖函數上加裝飾器@csrf_exempt. 與csrf_exempt(view)這麼寫和在視圖函數上加裝飾器是如出一轍的.
# urls.py中這種寫法本質就是返回的views.test, 只是在原來基礎之上不修改的調用方式, 以及原代碼的狀況下, 去除了csrf認證
path('test/', csrf_exempt(views.test)),