POST(CREATE):在服務(wù)器新建一個資源。
PUT(UPDATE):在服務(wù)器更新資源(客戶端提供改變后的完整資源)。
PATCH(UPDATE):在服務(wù)器更新資源(客戶端提供改變的屬性)。
DELETE(DELETE):從服務(wù)器刪除資源。
HEAD:獲取資源的元數(shù)據(jù)。
OPTIONS:獲取信息,關(guān)于資源的哪些屬性是客戶端可以改變的

6.過濾信息(Filtering)如果記錄數(shù)量很多,服務(wù)器不可能都返回給用戶。API應(yīng)該提供參數(shù),過濾返回結(jié)果。
下面是一些常見的參數(shù)。

https://api.example.com/v1/zoos?limit=10:指定返回記錄的數(shù)量
https://api.example.com/v1/zoos?offset=10:指定返回記錄的開始位置
https://api.example.com/v1/zoos?page=2&per_page=100:指定第幾頁,以及每頁的記錄數(shù)
https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回結(jié)果按照哪個屬性排序,以及排序順序
https://api.example.com/v1/zoos?animal_type_id=1:指定篩選條件

參數(shù)的設(shè)計允許存在冗余,即允許API路徑和URL參數(shù)偶爾有重復(fù)。比如,GET /zoo/ID/animals 與 GET /animals?zoo_id=ID 的含義是相同的。
7.狀態(tài)碼
服務(wù)器向用戶返回的狀態(tài)碼和提示信息,常見的有以下一些(方括號中是該狀態(tài)碼對應(yīng)的HTTP動詞)。

200 OK - [GET]:服務(wù)器成功返回用戶請求的數(shù)據(jù),該操作是冪等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數(shù)據(jù)成功。
202 Accepted - [*]:表示一個請求已經(jīng)進入后臺排隊(異步任務(wù))
204 NO CONTENT - [DELETE]:用戶刪除數(shù)據(jù)成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發(fā)出的請求有錯誤,服務(wù)器沒有進行新建或修改數(shù)據(jù)的操作,該操作是冪等的。
401 Unauthorized - [*]:表示用戶沒有權(quán)限(令牌、用戶名、密碼錯誤)。
403 Forbidden - [*] 表示用戶得到授權(quán)(與401錯誤相對),但是訪問是被禁止的。
404 NOT FOUND - [*]:用戶發(fā)出的請求針對的是不存在的記錄,服務(wù)器沒有進行操作,該操作是冪等的。
406 Not Acceptable - [GET]:用戶請求的格式不可得(比如用戶請求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用戶請求的資源被永久刪除,且不會再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 當(dāng)創(chuàng)建一個對象時,發(fā)生一個驗證錯誤。
500 INTERNAL SERVER ERROR - [*]:服務(wù)器發(fā)生錯誤,用戶將無法判斷發(fā)出的請求是否成功。

狀態(tài)碼的完全列表參見:https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html。
8.錯誤信息
    如果狀態(tài)碼是4xx,就應(yīng)該向用戶返回出錯信息。一般來說,返回的信息中將error作為鍵名,出錯信息作為鍵值即可。
9.返回結(jié)果(盡量使用Json格式)
    針對不同操作,服務(wù)器向用戶返回的結(jié)果應(yīng)該符合以下規(guī)范。

GET /collection:返回資源對象的列表(數(shù)組)
GET /collection/resource:返回單個資源對象
POST /collection:返回新生成的資源對象
PUT /collection/resource:返回完整的資源對象
PATCH /collection/resource:返回完整的資源對象
DELETE /collection/resource:返回一個空文檔

10.超鏈接
    即返回結(jié)果中提供鏈接,連向其他API方法

三、Django restframework介紹

Django Rest Framework 是一個強大且靈活的工具包,基于restful 規(guī)范開發(fā),用以構(gòu)建Web API。可以在Django的基礎(chǔ)上迅速實現(xiàn)API,并且自身還帶有WEB的測試頁面,可以方便的測試自己的API,主要運用于前后端分離的WEB應(yīng)用中。序列化使用方法和Django的form組件很類似。

四、Django restframework生命周期

發(fā)送請求–>Django的wsgi–>中間件–>路由系統(tǒng)_執(zhí)行CBV的as_view(),就是執(zhí)行內(nèi)部的dispath方法–>在dispath內(nèi),對request封裝–>版本–>認(rèn)證–>權(quán)限–>限流–>視圖–>如果視圖用到緩存( request.data or request.query_params )就用到了 解析器–>視圖處理數(shù)據(jù),用到了序列化(對數(shù)據(jù)進行序列化或驗證) –>視圖返回數(shù)據(jù)可以用到分頁


五、安裝django restframework

1、安裝
pip install djangorestframework
2、配置setting
如果想要獲取一個圖形化的頁面,需要將 rest_framework 注冊到項目的INSTALL_APPS中。

INSTALLED_APPS = [
...
'rest_framework',
'api',
...
]

六、Django RESTful Framework案例


1、路由urls

from django.urls import path, include
from views import TestView
app_name = 'api'
urlpatterns = [
path('test/', TestView.as_view(), name='test')
]

2、視圖views

from django.http import JsonResponse
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
class TestView(APIView):
def dispatch(self, request, *args, **kwargs):
"""
請求到來之后,都要請求dispatch方法,dispath方法根據(jù)不同的請求方式出發(fā)get/post/put等方法
注意:APIView中,dispath方法有好多好多功能
"""
return super().dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
data = {
"status": 200,
'data': 'get success'
}
return Response(data, status=201)
def post(self, request, *args, **kwargs):
data = {
'status': 200,
'data': 'post success'
}
return Response(data, status=201)

七、Djangorestframework視圖分類


視圖類 GenericAPIView:包含兩大視圖類(APIView、GenericAPIView)
視圖工具類 mixins:包含五大工具類,六大工具方法
工具視圖類 generics:包含九大工具視圖類,一堆mixins工具類與GenericAPIView視圖基類組合
視圖集 viewsets:可自定義映射關(guān)系

八、視圖類 GenericAPIView

1.APIView
from rest_framework.views import APIView
繼承基本View,擁有View所有的功能
重寫了as_view()方法,禁用了csrf認(rèn)證
重寫dispatch,封裝請求、響應(yīng)、渲染、異常、解析、三大認(rèn)證模塊
封裝一堆屬性,可完成視圖類的局部配置

1、renderer_classes  渲染的類
2、parser_classes 解析轉(zhuǎn)換的類
3、authentication_classes 認(rèn)證的類
4、throttle_classes 節(jié)流的類,控制請求頻率
5、permission_classes 權(quán)限的類
6、content_negotiation_class 內(nèi)容過濾類
7、metadata_class 元信息的類
8、versioning_class 版本控制的類
9、as_view()


調(diào)用父類中的as_view ->dispatch方法
dispatch方法被重寫
initialize_request 使用django的request構(gòu)建了一個REST中的Request initial 

perform_authentication
  執(zhí)行用戶認(rèn)證,遍歷認(rèn)證器,如果認(rèn)證成功返回一個元祖,元祖中的第一個元素就是user,第二個元素就是auth,token
  check_permissions
  檢查權(quán)限,遍歷我們的權(quán)限檢測器,只要有一個權(quán)限檢測沒有通過,就直接顯示權(quán)限被拒絕,所有權(quán)限都滿足,才算是擁有權(quán)限。
  check_throttles 
  檢測頻率,遍歷頻率限制器,如果驗證不通過,就需要等待 
  csrf_exempt
  所有APIView的自雷都是csrf豁免的

2.GenericAPIView
from rest_framework.generics import GenericAPIView
繼承APIView,擁有APIView所有的功能
提供get_queryset方法:配置queryset類屬性,群查獲取QuerySet對象
提供get_object方法:配置lookup_url_kwarg類屬性,單查獲取單個對象
提供get_serializer方法:配置serializer_class類屬性,提供序列化類并使用自定義的序列化類序列化
總結(jié):GenericAPIView就是在APIView基礎(chǔ)上額外提供了三個方法和三個類屬性,如果不配合視圖工具類,則體現(xiàn)不出來優(yōu)勢所在
使用它的好處:視圖中的增刪改查邏輯其實大差不差,但操作的資源不一致(操作的資源指的是models模型類和序列化類),將資源形成配置,操作邏輯一致,就可以完成封裝。
群查

from rest_framework.generics import GenericAPIView
class ViewGenericAPIView(GenericAPIView):
# 配置關(guān)聯(lián)表的屬性
# 如果只寫models.Car.objects的話那就是manager對象,不是QuerySet對象
queryset = models.Car.objects.filter(is_delete=False).all()
# 配置使用的序列化類
serializer_class = serializer.CarModelSerializer
# 群查
def get(self,request,*args,**kwargs):
# 幫我們?nèi)ケ砝锩婺脭?shù)據(jù)
car_query = self.get_queryset()
# 幫我們?nèi)バ蛄谢?br /> car_ser = self.get_serializer(car_query,many=True)
return APIResponse(results=car_ser.data)

單查

from rest_framework.generics import GenericAPIView
class ViewGenericAPIView(GenericAPIView):
# 配置關(guān)聯(lián)表的屬性
# 如果只寫models.Car.objects的話那就是manager對象,不是QuerySet對象
queryset = models.Car.objects.filter(is_delete=False).all()
# 配置使用的序列化類
serializer_class = serializer.CarModelSerializer
# 配置查詢的條件為pk,單查走pk過濾的條件
lookup_url_kwarg = 'pk'
# 單查
def get(self,request,*args,**kwargs):
car_obj = self.get_object()
car_ser = self.get_serializer(car_obj)
return APIResponse(results=car_ser.data)

九、視圖工具類 mixins

在GenericAPIView的基礎(chǔ)上提供了五個類,六個方法六大接口(單查、群查、單增、單整體改、單局部改、單刪),使用的時候需要配合繼承GenericAPIView類
1.五大工具類

RetrieveModelMixin:單查類
ListModelMixin:群查類
CreateModelMixin:單增類
UpdateModelMixin:單整體和單局部改類
DestroyModelMixin:單刪類

2.六大工具方法

retrieve:單查方法
list:群查方法
create:單增方法
update:單整體改方法
partial_update:單局部改方法
destroy:單刪方法

3.使用mixins的六大工具方法

from rest_framework import mixins
class ViewMixinsAPIView(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
queryset = models.Car.objects.filter(is_delete=False).all()
serializer_class = serializer.CarModelSerializer
lookup_url_kwarg = 'pk'
# 單查群查
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
return self.retrieve(request, *args, **kwargs)
return self.list(request, *args, **kwargs)
# 單增
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
# 單整體改
def put(self,request, *args, **kwargs):
return self.update(request, *args, **kwargs)
# 單局部改
def patch(self,request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
# 單刪
def delete(self,request, *args, **kwargs):
# django中的刪除是真正的刪除
# 刪除接口一般是自己實現(xiàn)重寫到的,因為真正的業(yè)務(wù)不需要真正的刪除
pass
# django源代碼中是真的刪除
return self.destroy(request, *args, **kwargs)

十、工具視圖類 generics

工具類加視圖類的組合,只要繼承工具該類,就有響應(yīng)的方法,幫我們將不同的mixins工具類與GenericAPIView視圖類進行組合,我們不再需要繼承GenericAPIView類
不同的組合封裝成一個個的類,實現(xiàn)對應(yīng)的請求方法(getpostputpatchdelete),隨后就是用單查就繼承單查的接口,用群查就繼承群查的接口即可。
使用generics的工具類實現(xiàn)接口

from rest_framework import generics
class ViewGenericsAPIView(generics.RetrieveAPIView,
generics.ListAPIView,
generics.CreateAPIView,
generics.UpdateAPIView,
generics.DestroyAPIView):
# 單查和群查只能使用一個get,具體調(diào)用哪個要看繼承的順序
queryset = models.Car.objects.filter(is_delete=False).all()
serializer_class = serializer.CarModelSerializer
lookup_url_kwarg = 'pk'
# 有刪除需求的接口繼承DestroyAPIView,重寫destroy完成字段的刪除
def destroy(self, request, *args, **kwargs):
pass

十一、視圖集 viewsets

重寫as_view方法,增加action參數(shù)(可以完成路由層的請求方法映射關(guān)系)
可以在路由層中自定義請求方法的映射關(guān)系,可自定義路由層中請求方法的映射關(guān)系來實現(xiàn)接口。
路由層

url(r'^v5/cars/$', views.ViewViewsetsAPIView.as_view({
"get":"list",
"post":"create"
})),
url(r'^v5/cars/(?P<pk>\d+)/$', views.ViewViewsetsAPIView.as_view({
"get":"retrieve",
"put":"update",
"patch":"partial_update",
"delete":"destroy"
})),

視圖層

from rest_framework import viewsets
# 視圖集類
class ViewViewsetsAPIView(viewsets.ModelViewSet):
queryset = models.Car.objects.filter(is_delete=False).all()
serializer_class = serializer.CarModelSerializer
lookup_url_kwarg = 'pk'

十二、實現(xiàn)群增,群整體改,群局部改,群刪四個接口

 # 群整體改
def many_update(self,request,*args,**kwargs):
try:
pks = []
for dic in request.data:
pks.append(dic.pop('pk'))
car_query = models.Car.objects.filter(is_delete=False, pk__in=pks).all()
if len(pks) != len(car_query):
raise Exception('pk對象不存在')
except Exception as e:
return Response({'detail': '%s' % e}, status=400)
car_ser = self.get_serializer(instance=car_query,data=request.data,many=True)
car_ser.is_valid(raise_exception=True)
car_obj = car_ser.save()
return APIResponse(results=self.get_serializer(car_obj,many=True).data)
# 群局部改
def many_partial_update(self,request,*args,**kwargs):
try:
pks = []
for dic in request.data:
pks.append(dic.pop('pk'))
car_query = models.Car.objects.filter(is_delete=False, pk__in=pks).all()
if len(pks) != len(car_query):
raise Exception('pk對象不存在')
except Exception as e:
return Response({'detail': '%s' % e}, status=400)
car_ser = self.get_serializer(instance=car_query,data=request.data,many=True,partial=True)
car_ser.is_valid(raise_exception=True)
car_obj = car_ser.save()
return APIResponse(results=self.get_serializer(car_obj,many=True).data)
# 群刪
def many_destroy(self,request,*args,**kwargs):
pks = request.data
try:
rows = models.Car.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
except:
return APIResponse(1, '數(shù)據(jù)有誤')
if rows:
return APIResponse(msg='刪除成功')
return APIResponse(1, '刪除失敗')
# 群增和單增必須使用同一個接口,都要走create方法,重寫create方法,使用邏輯拆分
def create(self, request, *args, **kwargs):
if isinstance(request.data,list):
car_ser = self.get_serializer(data=request.data,many=True)
car_ser.is_valid(raise_exception=True)
car_obj = car_ser.save()
return APIResponse(msg="群增成功",results=self.get_serializer(car_obj,many=True).data)
return super().create(request, *args, **kwargs)
實現(xiàn)刪除只做字段的修改
# 解決2 destroy方法完成對字段的修改
def destroy(self, request, *args, **kwargs):
car_obj = self.get_object()
if not car_obj:
return APIResponse(1,msg="刪除失敗")
car_obj.is_delete = True
car_obj.save()
return APIResponse(msg="刪除成功")
實現(xiàn)返回信息包含數(shù)據(jù)狀態(tài)碼和狀態(tài)信息
# 解決3 群查有狀態(tài)碼和狀態(tài)信息,重寫list方法
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
return APIResponse(results=response.data)
# 重寫retrieve方法,單查有狀態(tài)碼和狀態(tài)信息
def retrieve(self, request, *args, **kwargs):
response = super().retrieve(request, *args, **kwargs)
return APIResponse(results=response.data)

后續(xù)我將針對Djangorestframework寫一系列文章,讓大家更好掌握使用,能寫出實用的后端接口。希望大家多多支持!

文章轉(zhuǎn)自微信公眾號@Python與Django學(xué)習(xí)

上一篇:

從ASP.NET Core WebApi添加Swagger報錯開始的探究

下一篇:

為 Django 配備 GraphQL API
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊

多API并行試用

數(shù)據(jù)驅(qū)動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費