一、首先什么是RESTful
- REST與技術(shù)無關(guān),代表的是一種軟件架構(gòu)風(fēng)格,REST是Representational State Transfer的簡稱,中文翻譯為“表征狀態(tài)轉(zhuǎn)移”
- REST從資源的角度類審視整個(gè)網(wǎng)絡(luò),它將分布在網(wǎng)絡(luò)中某個(gè)節(jié)點(diǎn)的資源通過URL進(jìn)行標(biāo)識,客戶端應(yīng)用通過URL來獲取資源的表征,獲得這些表征致使這些應(yīng)用轉(zhuǎn)變狀態(tài)
- 所有的數(shù)據(jù),不管是通過網(wǎng)絡(luò)獲取的還是操作數(shù)據(jù)庫獲得(增刪改查)的數(shù)據(jù),都是資源,將一切數(shù)據(jù)視為資源是REST區(qū)別與其他架構(gòu)風(fēng)格的最本質(zhì)屬性
- 對于REST這種面向資源的架構(gòu)風(fēng)格,有人提出一種全新的結(jié)構(gòu)理念,即:面向資源架構(gòu)(ROA:Resource Oriented Architecture)
- 對互聯(lián)網(wǎng)上的任意東西都可視為資源,他認(rèn)為一個(gè)url就是一個(gè)資源 比如:http://www.xxx.com/get_user/
二、資源與URI
- REST全稱是表述性狀態(tài)轉(zhuǎn)移,那究竟指的是什么的表述? 其實(shí)指的就是資源。任何事物,只要有被引用到的必要,它就是一個(gè)資源。
- 要讓一個(gè)資源可以被識別,需要有個(gè)唯一標(biāo)識,在Web中這個(gè)唯一標(biāo)識就是URI(Uniform Resource Identifier)。
- URI既可以看成是資源的地址,也可以看成是資源的名稱。如果某些信息沒有使用URI來表示,那它就不能算是一個(gè)資源, 只能算是資源的一些信息而已。URI的設(shè)計(jì)應(yīng)該遵循可尋址性原則,具有自描述性,需要在形式上給人以直覺上的關(guān)聯(lián)。
URI設(shè)計(jì)上的一些技巧:
- 使用_或-來讓URI可讀性更好
- 使用/來表示資源的層級關(guān)系
- 使用?用來過濾資源
- ,或;可以用來表示同級資源的關(guān)系
三、什么是API
API就是接口,提供的url。接口有兩個(gè)用途:
- 為別人提供服務(wù)
- 前后端分離,一個(gè)寫vue,一個(gè)寫后端,他們之間都是通過ajax請求
四、RESTful API設(shè)計(jì)
網(wǎng)絡(luò)應(yīng)用程序,分為前端和后端兩個(gè)部分。當(dāng)前的發(fā)展趨勢,就是前端設(shè)備層出不窮(手機(jī)、平板、桌面電腦、其他專用設(shè)備......)。
因此,必須有一種統(tǒng)一的機(jī)制,方便不同的前端設(shè)備與后端進(jìn)行通信。這導(dǎo)致API構(gòu)架的流行,甚至出現(xiàn)"API First"的設(shè)計(jì)思想。RESTful API是目前比較成熟的一套互聯(lián)網(wǎng)應(yīng)用程序的API設(shè)計(jì)理論。
關(guān)于URL的設(shè)計(jì)大都長篇大論,這里我就不一一贅述了,通過一個(gè)簡單的示例來說明,可能有不太符合的地,但是萬變理解其宗就好。
- 首先:http協(xié)議請求方式:GET、POST、DELETE、PUT、PATCH、OPTION、HEAD、TRACE
- 之前URL的設(shè)計(jì)大多都是這種類型,不符合RESTful規(guī)范:
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規(guī)范的URL設(shè)計(jì):
GET請求查看數(shù)據(jù):
127.0.0.1:8000/books
返回所有數(shù)據(jù)列表 :[{}, {}, {}]
GET請求查看單條數(shù)據(jù):
127.0.0.1:8000/books/1
返回查看的單條數(shù)據(jù){}
POST請求添加數(shù)據(jù):
127.0.0.1:8000/books
返回添加數(shù)據(jù) :{}
PUT請求更新pk = 1的數(shù)據(jù):
127.0.0.1:8000/books/1
返回更新后的數(shù)據(jù): {}
Delete請求刪除pk = 1的數(shù)據(jù):
127.0.0.1:8000/books/1
返回空
五、基于Django實(shí)現(xiàn)API之RestFramework框架
- RestFramework框架:基于Django幫助我們快速開發(fā)符合RESTful規(guī)范的接口框架。
- Django實(shí)現(xiàn)的API許多功能都需要我們自己開發(fā),未免太過麻煩,這時(shí)候Django restframework就給我們提供了方便,直接基于它來返回?cái)?shù)據(jù),總之原理都是一樣的,就是給一個(gè)接口也就是url,讓前端的人去請求這個(gè)url去獲取數(shù)據(jù),在頁面上顯示出來。這樣也就達(dá)到了前后端分離的效果。下面我們來看看基于Django Rest Framework框架。
- 首先下載Django Rest Framework,
pip3 install djangorestframework
Rest Framework框架大體上分為以下十部分內(nèi)容:
- (1) APIView
- (2) 解析器組件
- (3) 序列化組件
- (4) 視圖類(mixin)
- (5) 認(rèn)證組件
- (6) 權(quán)限組件
- (7) 頻率組件
- (8) 分頁組件
- (9) 響應(yīng)器組件
- (10) url注冊器
五|1 - APIView:
APIView的源碼執(zhí)行可以參考DjangoCBV的源碼執(zhí)行邏輯
一張圖了解一下APIView的源碼執(zhí)行流程吧:

五|2- 解析器組件
對請求的數(shù)據(jù)進(jìn)行解析:是針對請求體進(jìn)行解析的。表示服務(wù)器可以解析的數(shù)據(jù)格式的種類
先來看Django中的發(fā)送請求:
- view.py中post請求的執(zhí)行體:

- 如果是這樣的格式發(fā)送的數(shù)據(jù),在POST里面有值
Content-Type: application/url-encoding..... //數(shù)據(jù)格式
request.body # 請求體中的原生數(shù)據(jù)
request.POST

- 如果是發(fā)送的json的格式,在POST里面是沒有值的,在body里面有值,可通過decode,然后loads取值
Content-Type: application/json..... //數(shù)據(jù)格式
request.body # 請求體中的原生數(shù)據(jù)
request.POST

這種情況下每次都要decode(解碼),loads(反序列化),真的很麻煩,所以才有的解析器組件。彌補(bǔ)了django的缺點(diǎn)。
接下來我們先了解restframework的解析器使用方法:
- 1、可以在CBV試圖類中添加屬性:
parser_classes = [JSONParser/FormParser/....] #表示服務(wù)器可以解析的數(shù)據(jù)格式的種類 - 2、可以在sittings配置項(xiàng)中添加(當(dāng)然也可以在內(nèi)置的settings文件中配置)django其實(shí)有兩個(gè)settings文件:
需要用什么數(shù)據(jù)格式就添加什么數(shù)據(jù)格式
REST_FRAMEWORK={
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
),
}
-3、如果都沒有配置的話那就使用默認(rèn)的配置:
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
)
看到這可能就懵逼了,不過沒關(guān)系,這幾種方法其實(shí)都是因?yàn)榉治隽嗽创a之后得出的,下面就一起來分析一下源碼的執(zhí)行流程吧:
步驟一、先來看看Django RestFramework的發(fā)送請求:(和Django的對比發(fā)現(xiàn)不同)
- view.py中post請求的執(zhí)行體:

- 如果是這樣的格式發(fā)送的數(shù)據(jù),在POST里面有值
Content-Type: application/url-encoding..... //數(shù)據(jù)格式
request.body # 請求體中的原生數(shù)據(jù)
request.POST
request.data #reqest.data是APIView重裝request才有的,reqest.data取值的時(shí)候才執(zhí)行解析器組件

- 如果是發(fā)送的json的格式,在POST里面是沒有值的,在body里面有值,可通過decode,然后loads取值
Content-Type: application/json..... //數(shù)據(jù)格式
request.body # 請求體中的原生數(shù)據(jù)
request.POST
request.data #reqest.data是APIView重裝request才有的,reqest.data取值的時(shí)候才執(zhí)行解析器組件

步驟二、解析器源碼執(zhí)行流程:

五|3- 序列化組件
- 首先表結(jié)構(gòu):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建立一對多的關(guān)系,外鍵字段建立在多的一方
publish = models.ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE)
# 與Author表建立多對多的關(guān)系,ManyToManyField可以建在兩個(gè)模型中的任意一個(gè),自動創(chuàng)建第三張表
authors = models.ManyToManyField(to='Author', )
- 先看一下基于Django的CBV接口設(shè)計(jì)
缺點(diǎn):需要自己設(shè)計(jì)數(shù)據(jù)格式、需要自己做序列化操作、需要自己講不支持json序列化的數(shù)據(jù)類型轉(zhuǎn)化
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的序列化組件的接口設(shè)計(jì)
缺點(diǎn):只支持序列化,而不支持校驗(yàn)、錯誤提示等附加功能
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 的接口設(shè)計(jì)
DRF ( Django RestFramework ) Serializer的序列化方式可以類比Django的Form組件的使用
注意一點(diǎn):因?yàn)镾erializer和數(shù)據(jù)庫沒有實(shí)質(zhì)上的聯(lián)系,所以post請求時(shí)不能直接保存到數(shù)據(jù)庫
from rest_framework.views import APIView
from app001 import models
# rest_framework重裝的response
from rest_framework.response import Response
# 序列化組件的導(dǎo)入
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參數(shù)取出想要的關(guān)聯(lián)對象的任意字段
publish_name = serializers.CharField(source="publish.name",read_only=True)
publish_city = serializers.CharField(source="publish.city",read_only=True)
# 多對多字段,可以通過source參數(shù)取出所有關(guān)聯(lián)對象queryset集合,幾乎沒用
# authors = serializers.CharField(max_length=32, source="authors.all",read_only=True)
# 多對多字段,固定的書寫格式
authors = serializers.SerializerMethodField(read_only=True)
def get_authors(self, obj): # 函數(shù)命名必須是get_field形式,obj為當(dāng)前字段對象
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) # 靜態(tài)方法:解析數(shù)據(jù)工作
bs = BooklistSerializer(data=request.data)
if bs.is_valid(): # 校驗(yàn)
return Response(bs.data) # 序列化數(shù)據(jù)
else:
return Response(bs.errors) # 序列化錯誤信息
- 基于DRF ( Django RestFramework ) ModelSerializer 的接口設(shè)計(jì)
DRF ( Django RestFramework ) Serializer的序列化方式可以類比Django的ModelForm組件的使用
當(dāng)涉及到一對多或者多對多字段時(shí),我們可以通過自定制操作來獲得我們想要的數(shù)據(jù)形式,
更多更細(xì)相關(guān)序列化內(nèi)容請看:https://www.cnblogs.com/pyspark/p/8607801.html
class BooklistSerializer(serializers.ModelSerializer):
//serializers.ChoiceField字段也可以通過source="get_字段名_display"的方式取出對應(yīng)數(shù)字的中文簡介
//一對多字段,可以通過source參數(shù)取出想要的關(guān)聯(lián)對象的任意字段
//一對多字段,需要添加read_only=True參數(shù),這個(gè)參數(shù)在post請求時(shí)有用
publish_name = serializers.CharField(source="publish.name",read_only=True)
publish_city = serializers.CharField(source="publish.city",read_only=True)
// 多對多字段,固定的書寫格式
// 函數(shù)命名必須是get_field形式,obj為當(dāng)前字段對象
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}} //設(shè)置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):
// 靜態(tài)方法:解析數(shù)據(jù)工作
print(request.data)
//post請求時(shí)不僅僅是序列化了,還需要驗(yàn)證、保存等,必須在實(shí)例化時(shí)加上data
//post發(fā)送的是添加請求,單個(gè)對象many=False
bs = BooklistSerializer(data=request.data,many=False)
// 校驗(yàn)
if bs.is_valid():
bs.save() // create操作
return Response(bs.data) // 序列化數(shù)據(jù)
else:
return Response(bs.errors) // 序列化錯誤信息