天天看點

基于Django實作 RESTful API 之RestFramework架構1一、首先什麼是RESTful二、資源與URI三、什麼是API四、RESTful API設計五、基于Django實作API之RestFramework架構五|1 - APIView:五|2- 解析器元件五|3- 序列化元件

一、首先什麼是RESTful

  • REST與技術無關,代表的是一種軟體架構風格,REST是Representational State Transfer的簡稱,中文翻譯為“表征狀态轉移”
  • REST從資源的角度類審視整個網絡,它将分布在網絡中某個節點的資源通過URL進行辨別,用戶端應用通過URL來擷取資源的表征,獲得這些表征緻使這些應用轉變狀态
  • 所有的資料,不管是通過網絡擷取的還是操作資料庫獲得(增删改查)的資料,都是資源,将一切資料視為資源是REST差別與其他架構風格的最本質屬性
  • 對于REST這種面向資源的架構風格,有人提出一種全新的結構理念,即:面向資源架構(ROA:Resource Oriented Architecture)
  • 對網際網路上的任意東西都可視為資源,他認為一個url就是一個資源 比如: http://www.xxx.com/get_user/

二、資源與URI

  • REST全稱是表述性狀态轉移,那究竟指的是什麼的表述? 其實指的就是資源。任何事物,隻要有被引用到的必要,它就是一個資源。
  • 要讓一個資源可以被識别,需要有個唯一辨別,在Web中這個唯一辨別就是URI(Uniform Resource Identifier)。
  • URI既可以看成是資源的位址,也可以看成是資源的名稱。如果某些資訊沒有使用URI來表示,那它就不能算是一個資源, 隻能算是資源的一些資訊而已。URI的設計應該遵循可尋址性原則,具有自描述性,需要在形式上給人以直覺上的關聯。

URI設計上的一些技巧:

  • 使用_或-來讓URI可讀性更好
  • 使用/來表示資源的層級關系
  • 使用?用來過濾資源
  • ,或;可以用來表示同級資源的關系

三、什麼是API

API就是接口,提供的url。接口有兩個用途:

  • 為别人提供服務
  • 前後端分離,一個寫vue,一個寫後端,他們之間都是通過ajax請求

四、RESTful API設計

  • 網絡應用程式,分為前端和後端兩個部分。目前的發展趨勢,就是前端裝置層出不窮(手機、平闆、桌面電腦、其他專用裝置......)。
  • 是以,必須有一種統一的機制,友善不同的前端裝置與後端進行通信。這導緻API構架的流行,甚至出現 "API First" 的設計思想。 RESTful API 是目前比較成熟的一套網際網路應用程式的API設計理論。

關于URL的設計大都長篇大論,這裡我就不一一贅述了,通過一個簡單的示例來說明,可能有不太符合的地,但是萬變了解其宗就好。

  • 首先:http協定請求方式:GET、POST、DELETE、PUT、PATCH、OPTION、HEAD、TRACE
  • 之前URL的設計大多都是這種類型,不符合RESTful規範:
127.0.0.1:8000/books              //查
127.0.0.1:8000/books/add          //增
127.0.0.1:8000/books/change/1     //改
127.0.0.1:8000/books/delete/1     //删
           
  • 符合RESTful規範的URL設計:
GET請求檢視資料:
127.0.0.1:8000/books 
傳回所有資料清單 :[{}, {}, {}]

GET請求檢視單條資料:
127.0.0.1:8000/books/1 
傳回檢視的單條資料{}

POST請求添加資料:
127.0.0.1:8000/books 
傳回添加資料 :{}

PUT請求更新pk = 1的資料:
127.0.0.1:8000/books/1 
傳回更新後的資料: {}

Delete請求删除pk = 1的資料:
127.0.0.1:8000/books/1 
傳回空
           

五、基于Django實作API之RestFramework架構

- RestFramework架構:基于Django幫助我們快速開發符合RESTful規範的接口架構。

- Django實作的API許多功能都需要我們自己開發,未免太過麻煩,這時候Django restframework就給我們提供了友善,直接基于它來傳回資料,總之原理都是一樣的,就是給一個接口也就是url,讓前端的人去請求這個url去擷取資料,在頁面上顯示出來。這樣也就達到了前後端分離的效果。下面我們來看看基于Django Rest Framework架構。

  • 首先下載下傳Django Rest Framework,

    pip3 install djangorestframework

Rest Framework架構大體上分為以下十部分内容:

  • (1) APIView
  • (2) 解析器元件
  • (3) 序列化元件
  • (4) 視圖類(mixin)
  • (5) 認證元件
  • (6) 權限元件
  • (7) 頻率元件
  • (8) 分頁元件
  • (9) 響應器元件
  • (10) url注冊器

五|1 - APIView:

APIView的源碼執行可以參考DjangoCBV的源碼執行邏輯

一張圖了解一下APIView的源碼執行流程吧:

基于Django實作 RESTful API 之RestFramework架構1一、首先什麼是RESTful二、資源與URI三、什麼是API四、RESTful API設計五、基于Django實作API之RestFramework架構五|1 - APIView:五|2- 解析器元件五|3- 序列化元件

6_副本.png

五|2- 解析器元件

對請求的資料進行解析:是針對請求體進行解析的。表示伺服器可以解析的資料格式的種類

先來看Django中的發送請求:

- view.py中post請求的執行體:
基于Django實作 RESTful API 之RestFramework架構1一、首先什麼是RESTful二、資源與URI三、什麼是API四、RESTful API設計五、基于Django實作API之RestFramework架構五|1 - APIView:五|2- 解析器元件五|3- 序列化元件

2.png

- 如果是這樣的格式發送的資料,在POST裡面有值

Content-Type: application/url-encoding..... //資料格式

request.body # 請求體中的原生資料

request.POST

基于Django實作 RESTful API 之RestFramework架構1一、首先什麼是RESTful二、資源與URI三、什麼是API四、RESTful API設計五、基于Django實作API之RestFramework架構五|1 - APIView:五|2- 解析器元件五|3- 序列化元件

1.png

- 如果是發送的json的格式,在POST裡面是沒有值的,在body裡面有值,可通過decode,然後loads取值

Content-Type: application/json..... //資料格式

基于Django實作 RESTful API 之RestFramework架構1一、首先什麼是RESTful二、資源與URI三、什麼是API四、RESTful API設計五、基于Django實作API之RestFramework架構五|1 - APIView:五|2- 解析器元件五|3- 序列化元件

3.png

這種情況下每次都要decode(解碼),loads(反序列化),真的很麻煩,是以才有的解析器元件。彌補了django的缺點。

接下來我們先了解restframework的解析器使用方法:

  • 1、可以在CBV試圖類中添加屬性:

    parser_classes = [JSONParser/FormParser/....] #表示伺服器可以解析的資料格式的種類

  • 2、可以在sittings配置項中添加(當然也可以在内置的settings檔案中配置)django其實有兩個settings檔案:
需要用什麼資料格式就添加什麼資料格式
REST_FRAMEWORK={
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
    ),
}
           

-3、如果都沒有配置的話那就使用預設的配置:

'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    )
           

看到這可能就懵逼了,不過沒關系,這幾種方法其實都是因為分析了源碼之後得出的,下面就一起來分析一下源碼的執行流程吧:

步驟一、先來看看Django RestFramework的發送請求:(和Django的對比發現不同)

基于Django實作 RESTful API 之RestFramework架構1一、首先什麼是RESTful二、資源與URI三、什麼是API四、RESTful API設計五、基于Django實作API之RestFramework架構五|1 - APIView:五|2- 解析器元件五|3- 序列化元件

4.png

request.data #reqest.data是APIView重裝request才有的,reqest.data取值的時候才執行解析器元件

基于Django實作 RESTful API 之RestFramework架構1一、首先什麼是RESTful二、資源與URI三、什麼是API四、RESTful API設計五、基于Django實作API之RestFramework架構五|1 - APIView:五|2- 解析器元件五|3- 序列化元件

5.png

基于Django實作 RESTful API 之RestFramework架構1一、首先什麼是RESTful二、資源與URI三、什麼是API四、RESTful API設計五、基于Django實作API之RestFramework架構五|1 - APIView:五|2- 解析器元件五|3- 序列化元件

6.png

步驟二、解析器源碼執行流程:

基于Django實作 RESTful API 之RestFramework架構1一、首先什麼是RESTful二、資源與URI三、什麼是API四、RESTful API設計五、基于Django實作API之RestFramework架構五|1 - APIView:五|2- 解析器元件五|3- 序列化元件

解析器源碼執行流程.jpg

五|3- 序列化元件

- 首先表結構:models.py
from django.db import models

class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    def __str__(self):
        return self.name

class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name

class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    publishDate = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)

    # 與Publish建立一對多的關系,外鍵字段建立在多的一方
    publish = models.ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE)
    # 與Author表建立多對多的關系,ManyToManyField可以建在兩個模型中的任意一個,自動建立第三張表
    authors = models.ManyToManyField(to='Author', )
           
- 先看一下基于Django的CBV接口設計

缺點:需要自己設計資料格式、需要自己做序列化操作、需要自己講不支援json序列化的資料類型轉化

class Booklist(View):

    def get(self, request):
        book_obj = models.Book.objects.all()
        ret = []
        for obj in book_obj:
            ret.append({
                "title":obj.title,
                "price":"%s"%obj.price,
            })
        return HttpResponse(json.dumps(ret,ensure_ascii=False))
           
- 基于Django的序列化元件的接口設計

缺點:隻支援序列化,而不支援校驗、錯誤提示等附加功能

from django.core.serializers import serialize 

class Booklist(View):

    def get(self, request):
        book_obj = models.Book.objects.all()
        data = serialize("json", book_obj)
        return HttpResponse(data)
           
- 基于DRF ( Django RestFramework ) Serializer 的接口設計

DRF ( Django RestFramework ) Serializer的序列化方式可以類比Django的Form元件的使用

注意一點:因為Serializer和資料庫沒有實質上的聯系,是以post請求時不能直接儲存到資料庫

from rest_framework.views import APIView
from app001 import models
# rest_framework重裝的response
from rest_framework.response import Response
# 序列化元件的導入
from rest_framework import serializers

class BooklistSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=32)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    publishDate = serializers.DateTimeField()
    # 一對多字段,可以通過source參數取出想要的關聯對象的任意字段
    publish_name = serializers.CharField(source="publish.name",read_only=True)
    publish_city = serializers.CharField(source="publish.city",read_only=True)
    # 多對多字段,可以通過source參數取出所有關聯對象queryset集合,幾乎沒用
    # authors = serializers.CharField(max_length=32, source="authors.all",read_only=True)
    # 多對多字段,固定的書寫格式
    authors = serializers.SerializerMethodField(read_only=True)
    def get_authors(self, obj):  # 函數命名必須是get_field形式,obj為目前字段對象
        ret = []
        for obj in obj.authors.all():
            ret.append(obj.name)
        return ret

class Booklist(APIView):
    # 查 get
    def get(self, request):
        book_obj = models.Book.objects.all()
        bs = BooklistSerializer(book_obj, many=True)
        data = bs.data  # 序列化接口
        return Response(data)
    #增 post
    def post(self, request):
        print(request.data)  # 靜态方法:解析資料工作
        bs = BooklistSerializer(data=request.data)
        if bs.is_valid():  # 校驗
            return Response(bs.data)  # 序列化資料
        else:
            return Response(bs.errors)  # 序列化錯誤資訊

           
- 基于DRF ( Django RestFramework ) ModelSerializer 的接口設計

DRF ( Django RestFramework ) Serializer的序列化方式可以類比Django的ModelForm元件的使用

當涉及到一對多或者多對多字段時,我們可以通過自定制操作來獲得我們想要的資料形式,

更多更細相關序列化内容請看:

https://www.cnblogs.com/pyspark/p/8607801.html
class BooklistSerializer(serializers.ModelSerializer):

    //serializers.ChoiceField字段也可以通過source="get_字段名_display"的方式取出對應數字的中文簡介
    //一對多字段,可以通過source參數取出想要的關聯對象的任意字段
    //一對多字段,需要添加read_only=True參數,這個參數在post請求時有用

    publish_name = serializers.CharField(source="publish.name",read_only=True)
    publish_city = serializers.CharField(source="publish.city",read_only=True)

    // 多對多字段,固定的書寫格式
    // 函數命名必須是get_field形式,obj為目前字段對象

    authors = serializers.SerializerMethodField()
    def get_authors(self, obj):  
        ret = []
        for obj in obj.authors.all():
            ret.append(obj.name)
        return ret

    class Meta:
        model=models.Book
        fields="__all__"    //指定所有字段
        extra_kwargs={"publish":{"write_only":True},"authors":{"write_only":True}}   //設定post寫入的隻寫不讀字段


class Booklist(APIView):

    def get(self, request):
        book_obj = models.Book.objects.all()
        bs = BooklistSerializer(book_obj, many=True)
        data = bs.data  # 序列化接口
        return Response(data)

    def post(self, request):    
        // 靜态方法:解析資料工作
        print(request.data) 

        //post請求時不僅僅是序列化了,還需要驗證、儲存等,必須在執行個體化時加上data
        //post發送的是添加請求,單個對象many=False
        bs = BooklistSerializer(data=request.data,many=False) 

        // 校驗
        if bs.is_valid():  
            bs.save()                            // create操作
            return Response(bs.data)            // 序列化資料
        else:
            return Response(bs.errors)         // 序列化錯誤資訊
           

強調:API的設計符合RESTful規範(請求方式、url設計、傳回資料)