DAY96-Rest Framework(一)-RESTful規範、APIView、序列化元件
一、CBV原始碼分析
1.基礎配置
# 路由
from app01 import views
urlpatterns = [
url(r'^books/', views.Books.as_view()),
]
# 檢視
from django.views import View
class Books(View):
def get(self,request):
return HttpResponse('ok')
2.執行順序
# 第一步 # 請求通過url找到對應的類的as_view函式 #url(r'^books/', views.Books.as_view()), def as_view(cls, **initkwargs): def view(request, *args, **kwargs): # 將類所需的引數以及類賦值給self 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 # 第三步,執行當前類的dispatch方法並返回 return self.dispatch(request, *args, **kwargs) # 第二步,執行閉包函式view,把Books和路由的引數initkwargs傳入 view.view_class = cls view.view_initkwargs = initkwargs # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view # 最後返回view的記憶體地址,相當於執行過後的dispatch方法的返回值 # 也就是說,views.Books.as_view()是得到了返回的記憶體地址並加上()執行
dispatch
# 由第三步進入 # 由於自定義的Books沒有dispatch,會去繼承的父類裡找 def dispatch(self, request, *args, **kwargs): # http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] # 判斷request帶來的請求方式在不在列表裡 if request.method.lower() in self.http_method_names: # 如果在裡面,就把當前的請求方式加上()執行並把返回值賦給handler handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed # 最後返回handler的返回值 return handler(request, *args, **kwargs)
總結
1.Books.as_view
2.as_view裡的view
3.view裡的dispatch
4.dispatch會判斷你的請求方式並執行,最後返回結果response
5.view返回dispatch的執行結果
6.as_view返回view的記憶體地址
7.最後在url里加上()執行
二、resful規範
1.什麼是resful
- REST與技術無關,代表的是一種軟體架構風格,REST是Representational State Transfer的簡稱,中文翻譯為“表徵狀態轉移”
- 所有的資料,不過是通過網路獲取的還是操作(增刪改查)的資料,都是資源,將一切資料視為資源是REST區別與其他架構風格的最本質屬性
- 對於REST這種面向資源的架構風格,有人提出一種全新的結構理念,即:面向資源架構(ROA:Resource Oriented Architecture)
2.resful的10項規範
總是使用HTTPS協議
域名
將API部署在專用域名(存在跨域問題):https://api.example.com
簡單API:https://www.example.com/api/
版本控制
https://www.example.com/api/v1(v2)
請求頭裡攜帶版本號
路徑:由於是面向資源程式設計,字尾為名詞
method:比如說書本,就只有books的路由,怎麼區分增刪查改的操作,就靠不同的請求
GET :從伺服器取出資源(一項或多項)
POST :在伺服器新建一個資源
PUT :在伺服器更新資源(客戶端提供改變後的完整資源)
PATCH :在伺服器更新資源(客戶端提供改變的屬性)
DELETE :從伺服器刪除資源
條件過濾:可以通過url新增過濾條件
https://www.example.com/api/v1/books?page=2&per_page=100:指定第幾頁,以及每頁的記錄數
狀態碼
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':'xx錯誤', }
返回結果
GET:返回所有資料列表 POST:返回新增的資料 GET:返回單條資料 #https://www.example.com/api/v1/books/1 {id:1, 'name':'alex', 'salary':3000}, PUT:更新,返回完整的資源物件 {id:1, 'name':'alex', 'salary':3000}, PATCH:更新,返回完整的資源物件 {id:1, 'name':'alex', 'salary':3000}, DELETE:刪除 返回空
Hypermedia API:即返回結果中提供連結,連向其他API方法,使得使用者不查文件,也知道下一步應該做什麼。
{ status:100 msg:成功 url:127.0.0.1/books/1 } #核心:返回結果中提供連結
三、drf(django rest framwork)框架
它是一個app,要在咱的專案中用,只是快速的構建resful規範的介面
pip3 install djangorestframework
四、APIView原始碼分析
1.基礎配置
# 路由
from app01 import views
urlpatterns = [
url(r'^books/', views.Books.as_view()),
]
# 檢視
from rest_framework.views import APIView
from rest_framework.request import Request
from rest_framework.response import Response
class Books(APIView):
def get(self,request):
return HttpResponse('ok')
2.執行順序
# 執行順序大致與CBV的執行順序相同,有改動
def as_view(cls, **initkwargs):
# 呼叫父類APIView的as_view方法,APIView是繼承View
# APIView裡沒有as_view,也就是說,是呼叫View的as_view方法並把最終結果賦值給了view
view = super(APIView, cls).as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
# csrf_exempt區域性禁用
# 因為drf框架是不需要csrf認證的
return csrf_exempt(view)
# 第三步呼叫的dispatch從Books裡找,沒有就往上一層父類裡找,APIView裡有
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
# APIView的dispatch對request進一步的封裝
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs)
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
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
總結
1.Books(APIView).as_view (呼叫了View的as_view方法)
2.as_view裡的view
3.view裡的dispatch(從下往上找,APIView的dispatch)
4.APIView的dispatch先對原先的request進行封裝,然後判斷請求方式並執行,最後返回結果response
5.view返回dispatch的執行結果
6.as_view返回view的記憶體地址
7.最後在url里加上()執行
3.補充
hasattr(self, 'get')--判斷self類中是不是有該(get)方法
setattr(self,get,get_all):相當於把get函式,變成了get_all
__setatt___方法:賦予值時觸發
getattr(self, 'get'):拿到get函式的記憶體地址
__getatt__方法r:獲得值時觸發
五、序列化
方式一:for迴圈
class Books(View):
def get(self,request):
books = models.Books.objects.all()
ll = [{'name':book.name,'price':book.price} for book in books]
return JsonResponse(ll,safe=False)
方式二:django自帶的序列化
from django.core import serializers
class Books(View):
def get(self,request):
books = models.Books.objects.all()
ret = serializers.serialize('json',books)
return HttpResponse(ret)
方式三:drf提供的序列化元件
from rest_framework.serializers import Serializer
from rest_framework import serializers
class BooksSerializer(Serializer):
name = serializers.CharField(max_length=32)
price = serializers.CharField(max_length=32)
class Books(APIView):
def get(self, request):
books = models.Books.objects.all()
# instance:要序列化的物件(可能是queryset,也可能是單個物件) # many:如果是queryset---True,,如果是單個物件--False
ret = BooksSerializer(instance=books,many=True)
# 生成的是列表,需要轉成JSON格式
#[OrderedDict([('name', 'ab'), ('price', '12')]), 。。。。。]
return JsonResponse(ret.data,safe=False)