1. 程式人生 > >DAY96-Rest Framework(一)-RESTful規範、APIView、序列化元件

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)

    ​ 請求頭裡攜帶版本號

  • 路徑:由於是面向資源程式設計,字尾為名詞

    https://www.example.com/api/v1/books

    https://www.example.com/api/v2/students

  • 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)