restful 規範與 drf 的安裝使用 & drf 中 APIView 源碼分析

来源:https://www.cnblogs.com/elijah-li/archive/2022/03/29/16071973.html
-Advertisement-
Play Games

內容概要 web 開發模式 API 介面 postman 測試軟體的使用 restful 規範 drf 的安裝與使用 cbv 的 View 源碼分析 APIView 源碼分析 drf 的 Request 類 drf 的 APIView 類執行過程 內容詳細 web 開發模式 1、前後端不分離 在開發 ...


內容概要

  • web 開發模式
  • API 介面
  • postman 測試軟體的使用
  • restful 規範
  • drf 的安裝與使用
  • cbv 的 View 源碼分析
  • APIView 源碼分析
  • drf 的 Request 類
  • drf 的 APIView 類執行過程

內容詳細

web 開發模式

1、前後端不分離

在開發一個網站的過程中,前端頁面需要使用後端框架的模板語法(DTL) 來渲染,比如 Django 自帶的模板語法或者 jinjia2,這種前端頁面在後端渲染完成之後才會把頁面文檔傳送給前端

image

2、前後端分離

目前主流的開發模式,這種模式中前端先在後端的靜態文件伺服器(nfs)中獲取靜態文件(static 中的HTML、CSS、JS代碼),需要數據的時候向後端發送請求只獲取json格式的數據,再在前端運用js的BOM與DOM操作對頁面進行渲染。

這樣便實現了前後端分離,前端只需要從後端獲取一定格式的數據,那麼前端就可以是一個網頁、app或者小程式,提高開發水平。

image

API 介面

簡介: api 介面是前後端交互數據的媒介

api 介面包含:

  • 1、url 地址: 向後端請求數據的地址
  • 2、請求方式 : get、post、put、patch、delete
  • 3、請求參數:在 url 地址後面緊跟著的 ?name='elijah',可以看作是過濾條件
  • 4、響應結果:包括響應首行(響應狀態碼)、響應頭、響應體(json格式數據)

postman 測試軟體的使用

過去我們開髮網站開放出來的介面一般使用瀏覽器發送get請求來進行測試,但基於api介面的restful設計規範,我們還需要使用 post請求、put請求等,而瀏覽器只能發送 get請求

postman 是一種測試介面共組,在 postman 中可以滿足我們的測試需求

市面上也有許多測試軟體(postwoman),我們使用主流的postman

下載地址https://www.getpostman.com/downloads/

使用:

1、發送請求

image

前後端數據交互的編碼格式:

  • urlencoded:正常的post請求提交數據:name=elijah
  • formdata:post請求上傳文件:帶文件二進位形式
  • json:在body體中的數據格式為:{"name":"elijah","age":18} (用的多)

發起請求時,可以在 body 中書寫請求體:

image

image

2、建立集合批量發起測試

image

image

image

同時,這個批量測試也支持導出文件,然後發送給別人,再從文件中導出

image

restful 規範

REST與技術無關,代表的是一種軟體架構風格,REST是Representational State Transfer的簡稱,中文翻譯為“表徵狀態轉移”或“表現層狀態轉化”。它首次出現在2000年Roy Fielding的博士論文中。

在前後端分離的開發模式中,為了方便數據交互,我們在設計前後端進行數據交互的 api 介面時,需要符合 restful 規範,它是一種寫前後端分離的標準

對於REST這種面向資源的架構風格,有人提出一種全新的結構理念,即:面向資源架構(ROA:Resource Oriented Architecture)

10條 restful 規範:

1、通信協議一般使用 https 協議,為保障數據安全

2、設計的介面地址是可以讓人一眼看出來是 api 介面(在介面中帶api字眼)

3、多數據版本共存

介面更新之後,老版本的介面依舊一起使用,等過了期限才棄用老版本(維護老版本介面),以便可以留存更多用戶。

4、交互數據即是資源,使用名詞(可以是複數)

不建議使用動詞,如 get_resource ,除非是 login 或者 register 這種介面

5、用不同的請求方式表示不同的資源操作

  • get: 獲取資源
  • post: 新增資源
  • put: 修改資源(全局修改)
  • patch: 修改資源(局部修改)
  • delete: 刪除資源

6、過濾,通過在url上傳參的形式傳遞搜索條件

7、響應狀態碼(http的響應狀態碼,響應體的json數據中帶狀態碼)

http 協議的狀態碼:

更多狀態碼請參考: https://www.cnblogs.com/elijah-li/p/16069638.html

1xx:請求正在處理
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 - [*]:伺服器發生錯誤,用戶將無法判斷發出的請求是否成功。

更多狀態碼請參考: https://www.cnblogs.com/elijah-li/p/16069638.html

服務端自定義的狀態碼

響應體中返回json格式數據,數據中有 服務端自定義的狀態碼(code,status)

  • 1001 :用戶名錯誤
  • 1002 :沒有許可權

8、返回錯誤信息(錯誤處理)

返回數據是json格式,帶狀態碼和錯誤信息

{
    code: 1002
    error: "Invalid API key"
}

9、不同的請求方式(不同操作)應該返回不同的資源

  • get:/collection/resources 獲取多個資源 --》 返回資源對象的列表 [{name:elijah,age:18},{name:pyy,age:33}]
  • get /collection/resource 返回單個資源對象 {name:elijah,age:18}
  • post: 新增資源 --》 返回新增的資源對象 {name:elijah,age:18}
  • put: 修改資源(全局修改) --》 返回修改的資源對象 {name:elijah,age:18}
  • patch: 修改資源(局部修改) --》 返回修改的資源對象 {name:elijah,age:18}
  • delete: 刪除資源 --》 返回空文檔(或者錯誤文檔) {code:100,msg:刪除成功}

10、返回資源中要跳轉的鏈接地址

{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",   '''連接地址'''
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

drf 的安裝與使用

1、安裝 djangorestframework

pip install djangorestframework==3.10.3

2、在 settings.py 文件中 註冊 rest_framework

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rest_framework',
]

3、在 models.py 中寫表模型

class Book(models.Model):
    name = models.CharField(verbose_name='書名', max_length=32)
    price = models.DecimalField(verbose_name='價格', max_digits=5, decimal_places=2)
    author = models.CharField(verbose_name='作者', max_length=32)

    class Meta:
        verbose_name_plural = '書籍表'

4、新建一個序列化類

在應用文件夾下創建一個 ser.py 作為序列化模塊

from rest_framework.serializers import ModelSerializer
from app01.models import Book


class BookModelSerializer(ModelSerializer):  # 繼承的是 ModelSerializer
    class Meta:
        model = Book
        fields = '__all__'  # 註意別漏寫 fields

5、書寫視圖函數(CBV)

from rest_framework.viewsets import ModelViewSet
from .ser import BookModelSerializer, Book


# Create your views here.


class BookModelViewSet(ModelViewSet):  # 繼承的是 ModelViewSet
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer

6、書寫 url

from app01 import views
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('books', views.BookModelViewSet)


urlpatterns = [
    path('admin/', admin.site.urls),
]
urlpatterns += router.urls

9、遷移資料庫

python manage.py makemigrations
python manage.py migrate

10、在瀏覽器中測試介面

image

11、在 postman 中測試介面

註意: 在發送 put 請求(修改資源)、patch 請求(修改資源)、delete 請求(刪除資源)時,得在名詞後面添加具體的資源 id 值,並且要加上 “/” ,因為 postman 不會自動加斜桿

獲取資源

image

新增資源:

image

修改資源:

image

刪除資源:

image

cbv 的 View 源碼分析

從路由文件 urls.py 的調用語句中看起

urlpatterns = [
    path('CBV/', views.MyClass.as_view()),
]
# as_view() 函數加括弧優先調用 as_view函數

按住 ctrl 鍵,滑鼠點擊查看 as_view 源碼

@classonlymethod
def as_view(cls, **initkwargs):
    def view(request, *args, **kwargs):
        self = cls(**initkwargs)		# self 是我們自定義類產生的對象
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.setup(request, *args, **kwargs)
        if not hasattr(self, 'request'):	# 自定義類必須接收 request 對象,否則主動報錯
            raise AttributeError(
                "%s instance has no 'request' attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
         return self.dispatch(request, *args, **kwargs)		# view 函數調用 View 類中的dispath函數
    # ... 中間省略部分源碼
    return view		# 返回view函數對象

從源碼中可以看出,as_view 調用之後得到的是 view 函數對象,這是個閉包函數,當視圖函數被觸發,調用的是 view函數,view函數return一個 dispatch 函數調用結果

我們再查看 dispatch 的源碼:

http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']


def dispatch(self, request, *args, **kwargs):
    # Try to dispatch to the right method; if a method doesn't exist,
    # defer to the error handler. Also defer to the error handler if the
    # request method isn't on the approved list.
    if request.method.lower() in self.http_method_names:	# 如果是request中的屬性,則用反射調用自身的響應的函數
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)

APIView 源碼分析

APIView 是 rest_framework.views 中的一個類,是 drf 提供給我們更多功能的視圖函數類,也繼承了 Django 的 View

基於 CBV 先定義一個視圖函數

views.py :

from rest_framework.views import APIView

class BookAPIView(APIView):
    def get(self, request):
        pass

    def post(self, request):
        pass

urls.py :

urlpatterns = [
    path('admin/', admin.site.urls),
    path('book/',views.BookAPIView.as_view())  # 調用 as_view() 返回的是 view 函數的記憶體地址
]

調用的是 APIView 的 as_view 方法:

APIView 類繼承的是 Django 的 View,所以 super().as_view(**initkwargs) 調用了父類(View)中的 as_view,返回的是 View 中 as_view 返回的 view,在 view 函數里調用的 self.dispatch(request, *args, kwargs) 根據類的查找順序,調用的就是 APIView 中的 dispatch

class APIView(View):
    @classmethod
    def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs
        return csrf_exempt(view)  # 所有繼承了 APIView 的視圖函數都忽略了 csrf 認證
  • 調用了 APIView 的 dispatch方法
  • 忽略了視圖函數的 csrf 認證
csrf_exempt(index) 相當於
@csrf_exempt
def index(request)
	pass
# index=csrf_exempt(index)

APIView 中的 dispatch:

    def dispatch(self, request, *args, **kwargs):
        # 重寫了 Django 傳過來的 request 請求數據對象,給request增添了新屬性
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request

        try:
            # 進行三大認證
            self.initial(request, *args, **kwargs)
            # 反射機制調用視圖函數類中的方法,與原生 dispatch 一致
            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)

        # 處理放回數據,具有 drf 特色的頁面
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

APIView 中的 initialize_request:

對原生的 request 進行處理,新增了一些功能和屬性

    def initialize_request(self, request, *args, **kwargs):
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

initialize_request 中的 Request():

把原生的 request 賦給了 _request,原 request 請求對象的方法在 _request 中獲取就可以

class Request:
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):

        self._request = request
        self._data = Empty
request 的變化

新的:<class 'rest_framework.request.Request'>
老的:<class 'django.core.handlers.wsgi.WSGIRequest'>

三大認證:

# 三大認證人如何走的
self.initial(request, *args, **kwargs)---》APIView的
核心代碼:
   self.perform_authentication(request)  # 認證
   self.check_permissions(request)   #許可權
   self.check_throttles(request) # 頻率

drf 的 Request 類

重寫了 request 請求數據對象之後,原生的 request 方法一樣能用,因為 Request 類中的 getattr 方法(對象的 '.' 點攔截)中用放射機制獲取了原生 request 的所有屬性

Request --> __getattr__

    def __getattr__(self, attr):
        try:
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)

前端post請求傳入的數據,在原來的request.POST中只能處理urlencoded和formdata編碼格式,json格式不能處理。

而 Request 類實例化之後,提供了一個 data 方法,無論前端用什麼編碼post提交的數據,都從 request.data 中獲取。

    @property
    def data(self):
        if not _hasattr(self, '_full_data'):
            self._load_data_and_files()
        return self._full_data

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • finally的特點 finally:被finally控制的語句體一定會執行 * 註意:如果在執行到finally之前jvm退出了,就不能執行了。 * * A:格式 * try...catch...finally... * B:用於釋放資源,在IO流操作和資料庫操作中會見到 package cn.i ...
  • 練習: 存儲學生對象並遍歷,創建TreeSet集合使用無參構造方法,並按照年齡從小到大的順序排序,若年齡相同再按照姓名的字母順序排序 分析: 1.創建學生類,成員變數name,age;無參構造,帶參構造;get\set方法; 2.創建測試類,添加數據併進行排序;直接排序會報錯 3.需要Student ...
  • 過濾器就是過濾條件,對已經定位到數組中的 DOM 對象進行過濾篩選,過濾條件不能獨立出現在 jquery 函數,如果使用只能出現在選擇器後方 ...
  • 背景 很多時候,我們項目在開發環境和生成環境的環境配置是不一樣的,例如,資料庫配置,在開發的時候,我們一般用測試資料庫,而在生產環境的時候,我們是用正式的數據,這時候,我們可以利用profile在不同的環境下配置用不同的配置文件或者不同的配置。 解決方案 spring boot允許你通過命名約定按照 ...
  • 程式的異常:Throwable * 嚴重問題:Error 我們不處理。這種問題一般都是很嚴重的,比如說記憶體溢出。 * 問題:Exception * A:編譯期問題:不是RuntimeException的異常 必須進行處理的,因為你不處理,編譯就不能通過。 * B:運行期問題:RuntimeExcep ...
  • 一、前言 掃描件一直受大眾青睞,任何紙質資料在掃描之後進行存檔,想使用時手機就能打開,省心省力。但是掃描件的優點也恰恰造成了它的一個缺點,因為是通過電子設備掃描,所以出來的是圖像,如果想要處理文件上的內容,直接操作是無法實現的。 那要是想要引用其中的內容怎麼辦呢?別擔心,Python幫你解決問題。 ...
  • 一、序言 Spring Cache是Spring體系下標準化緩存框架。Spring Cache有如下優勢: 緩存品種多 支持緩存品種多,常見緩存Redis、EhCache、Caffeine均支持。它們之間既能獨立使用,也能組合使用。 平滑遷移 Spring內部支持的緩存,可實現無縫平滑遷移,無需修改 ...
  • 首先 相信有很多小伙伴都喜歡玩抖音吧,最近抖音張同學突然火了,兩個月漲粉一千多萬。看了他的視頻,滿滿的生活氣息,讓人有一種家的感覺。這就讓我很感興趣了,必須得用Python對他分析一下。 今天這篇文章,我抓取了張同學的視頻的評論數據,想從文本分析的角度,挖掘一下大家對張同學感興趣的點。 張同學 10 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...