django-rest-framework(drf入門)
阿新 • • 發佈:2021-06-12
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®ion=%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類,流程,你走一遍,整理成自己的話作業