1. 程式人生 > 其它 >django-rest-framework(drf入門)

django-rest-framework(drf入門)

django-rest-framework

restful規範,

drf入門,檢視,序列化(最重要)響應,許可權,認證頻率,過濾,分頁

今日內容

1 web開發模式

#前後端混合開發(前後端不分離):返回的是html的內容,需要寫模板
#前後端分離:只專注於寫後端介面,返回json,xml格式資料
# xml格式
<xml>
<name>lqz</name>
</xml>
# json
{"name":"lqz"}
​
# java---》jsp
https://www.pearvideo.com/category_loading.jsp
#php寫的
http://www.aa7a.cn/user.php # python寫的 http://www.aa7a.cn/user.html ​ ​ ​ ​ #什麼是動態頁面(查資料庫的),什麼是靜態頁面(靜止的html) #頁面靜態化

2 api介面

#通過網路,規定了前後臺資訊互動規則的url連結,也就是前後臺資訊互動的媒介
#百度地圖的api介面 
https://api.map.baidu.com/place/v2/search?

ak=6E823f587c95f0148c19993539b99295&region=%E4%B8%8A%E6%B5%B7&query=%E8%82%AF%E5%BE%B7%E5%9F%BA

&output=xml #格式

3 postman的使用

# postman是目前最好用的,模擬傳送http請求的工具
# 雙擊安裝,安裝完成自動開啟

# 解析json的網站
http://www.json.cn/

#請求頭中User-Agent:客戶端的型別
# 請求頭中加其他引數:
# 批量介面匯出和測試(實操一下)

post寫入請求中(上述錯誤):是直接在body請求體中書寫

4 Restful規範(重點 ⑩條)

REST全稱是Representational State Transfer,中文意思是表述(編者注:通常譯為表徵性狀態轉移)。 它首次出現在2000年Roy Fielding的博士論文中。
​
RESTful是一種定義Web API介面的設計風格,尤其適用於前後端分離的應用模式中。
​
這種風格的理念認為後端開發任務就是提供資料的,對外提供的是資料資源的訪問介面,所以在定義介面時,客戶端訪問的URL路徑就表示這種要操作的資料資源。
​
事實上,我們可以使用任何一個框架都可以實現符合restful規範的API介面。
​
# 抓包工具:fiddler,charles # 10條規範 1 資料的安全保障:url連結一般都採用https協議進行傳輸 注:採用https協議,可以提高資料互動過程中的安全性 2 介面特徵表現,一看就知道是個api介面 - 用api關鍵字標識介面url: - [https://api.baidu.com](https://api.baidu.com/) - https://www.baidu.com/api 注:看到api字眼,就代表該請求url連結是完成前後臺數據互動的 -路飛的介面:https://api.luffycity.com/api/v1/course/free/ 3 多資料版本共存 - 在url連結中標識資料版本 - https://api.baidu.com/v1 - https://api.baidu.com/v2 注:url連結中的v1、v2就是不同資料版本的體現(只有在一種資料資源有多版本情況下) 4 資料即是資源,均使用名詞(可複數) - 介面一般都是完成前後臺數據的互動,互動的資料我們稱之為資源 - https://api.baidu.com/users - https://api.baidu.com/books - https://api.baidu.com/book ​ 注:一般提倡用資源的複數形式,在url連結中獎勵不要出現操作資源的動詞,錯誤示範: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 響應狀態碼 7.1 正常響應 - 響應狀態碼2xx - 200:常規請求 - 201:建立成功 7.2 重定向響應 - 響應狀態碼3xx - 301:永久重定向 - 302:暫時重定向 7.3 客戶端異常 - 響應狀態碼4xx - 403:請求無許可權 - 404:請求路徑不存在 - 405:請求方法不存在 7.4 伺服器異常 - 響應狀態碼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" } ... ] }

5 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),                                2.0到版本的路由層
        ]
        #這是什麼意思?兩個列表相加
        # router.urls  列表
        urlpatterns += router.urls
        
    6 啟動,在postman中測試即可(介面)
 

3 cbv原始碼

# ModelViewSet繼承View(django原生View)
# APIView繼承了View
# 先讀View的原始碼
from django.views import View
​
# urls.py
path('books1/', views.Books.as_view()),  #在這個地方應該寫個函式記憶體地址,views.Books.as_view()執行完,是個函式記憶體地址,as_view是一個類方法,類直接來呼叫,會把類自動傳入
放了一個view的記憶體地址(View--》as_view--》內層函式)
​
# 請求來了,如果路徑匹配,會執行,  函式記憶體地址(request)
def view(request, *args, **kwargs):
    #request是當次請求的request
    self = cls(**initkwargs)  #例項化得到一個物件,Book物件
    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)
​
 
def dispatch(self, request, *args, **kwargs):
        #request是當次請求的request   self是book物件
        if request.method.lower() in self.http_method_names:
            #handler現在是:
            handler=getattr(self,'get'),你寫的Book類的get方法的記憶體地址
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)  #執行get(request)

4 APIView原始碼分析

#from rest_framework.views import APIView
# urls.py
path('booksapiview/', views.BooksAPIView.as_view()),  #在這個地方應該寫個函式記憶體地址
#APIView的as_view方法(類的繫結方法)
   def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs)  # 呼叫父類(View)的as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs
        # 以後所有的請求,都沒有csrf認證了,只要繼承了APIView,就沒有csrf的認證
        return csrf_exempt(view)
 
​
#請求來了---》路由匹配上---》view(request)---》呼叫了self.dispatch(),會執行apiview的dispatch
    
# APIView的dispatch方法
    def dispatch(self, request, *args, **kwargs):
​
        self.args = args
        self.kwargs = kwargs
        # 重新包裝成一個request物件,以後再用的request物件,就是新的request物件了
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?
try:
            # 三大認證模組
            self.initial(request, *args, **kwargs)
​
            # Get the appropriate handler method
            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
   
# 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)
 

​
from rest_framework.request import Request
# 只要繼承了APIView,檢視類中的request物件,都是新的,也就是上面那個request的物件了
# 老的request在新的request._request
# 以後使用reqeust物件,就像使用之前的request是一模一樣(因為重寫了__getattr__方法)
  def __getattr__(self, attr):
        try:
            return getattr(self._request, attr) #通過反射,取原生的request物件,取出屬性或方法
        except AttributeError:
            return self.__getattribute__(attr)
​
 # request.data 感覺是個資料屬性,其實是個方法,@property,修飾了
    它是一個字典,post請求不管使用什麼編碼,傳過來的資料,都在request.data
 #get請求傳過來資料,從哪取?
    request.GET
    @property
    def query_params(self):
        """
        More semantically correct name for request.GET.
        """
        return self._request.GET
    
    #檢視類中
     print(request.query_params)  #get請求,地址中的引數
     # 原來在
     print(request.GET)

補充

1 檢視原始碼

2 一切皆物件(可以放值)

def foo(a,b):
    return a+b
​
foo.name='lqz'  #由於一切皆物件,函式也是個物件,物件放值
print(foo(2,3))
​
print(foo.name)

3 區域性禁用csrf(的其他使用裝飾器)

# 在檢視函式上加裝飾器@csrf_exempt
# csrf_exempt(view)這麼寫和在檢視函式上加裝飾器是一毛一樣的
#urls.py中看到這種寫法
path('tset/', csrf_exempt(views.test)),

1 用postman,用django寫幾個介面,測試,匯出檔案
2 新建一個圖書表,5個符合restful規範的介面,用CBV的APIView實現
3 rest_framework的Resquest類和APIView類,流程,你走一遍,整理成自己的話
作業