基于Django實(shí)現(xiàn) RESTful API 之RestFramework框架1

一绿饵、首先什么是RESTful

  • REST與技術(shù)無關(guān),代表的是一種軟件架構(gòu)風(fēng)格,REST是Representational State Transfer的簡(jiǎn)稱厘擂,中文翻譯為“表征狀態(tài)轉(zhuǎn)移”
  • REST從資源的角度類審視整個(gè)網(wǎng)絡(luò),它將分布在網(wǎng)絡(luò)中某個(gè)節(jié)點(diǎn)的資源通過URL進(jìn)行標(biāo)識(shí)锰瘸,客戶端應(yīng)用通過URL來獲取資源的表征刽严,獲得這些表征致使這些應(yīng)用轉(zhuǎn)變狀態(tài)
  • 所有的數(shù)據(jù),不管是通過網(wǎng)絡(luò)獲取的還是操作數(shù)據(jù)庫(kù)獲得(增刪改查)的數(shù)據(jù)避凝,都是資源舞萄,將一切數(shù)據(jù)視為資源是REST區(qū)別與其他架構(gòu)風(fēng)格的最本質(zhì)屬性
  • 對(duì)于REST這種面向資源的架構(gòu)風(fēng)格,有人提出一種全新的結(jié)構(gòu)理念管削,即:面向資源架構(gòu)ROA:Resource Oriented Architecture)
  • 對(duì)互聯(lián)網(wǎng)上的任意東西都可視為資源倒脓,他認(rèn)為一個(gè)url就是一個(gè)資源 比如:http://www.xxx.com/get_user/

二、資源與URI

  • REST全稱是表述性狀態(tài)轉(zhuǎn)移佩谣,那究竟指的是什么的表述? 其實(shí)指的就是資源把还。任何事物,只要有被引用到的必要茸俭,它就是一個(gè)資源吊履。
  • 要讓一個(gè)資源可以被識(shí)別,需要有個(gè)唯一標(biāo)識(shí)调鬓,在Web中這個(gè)唯一標(biāo)識(shí)就是URI(Uniform Resource Identifier)艇炎。
  • URI既可以看成是資源的地址,也可以看成是資源的名稱腾窝。如果某些信息沒有使用URI來表示缀踪,那它就不能算是一個(gè)資源, 只能算是資源的一些信息而已虹脯。URI的設(shè)計(jì)應(yīng)該遵循可尋址性原則驴娃,具有自描述性,需要在形式上給人以直覺上的關(guān)聯(lián)循集。
URI設(shè)計(jì)上的一些技巧:
  • 使用_或-來讓URI可讀性更好
  • 使用/來表示資源的層級(jí)關(guān)系
  • 使用?用來過濾資源
  • ,或;可以用來表示同級(jí)資源的關(guān)系

三唇敞、什么是API

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

  • 為別人提供服務(wù)
  • 前后端分離疆柔,一個(gè)寫vue咒精,一個(gè)寫后端,他們之間都是通過ajax請(qǐng)求

四旷档、RESTful API設(shè)計(jì)

  • 網(wǎng)絡(luò)應(yīng)用程序模叙,分為前端和后端兩個(gè)部分。當(dāng)前的發(fā)展趨勢(shì)鞋屈,就是前端設(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ì)大都長(zhǎng)篇大論盗迟,這里我就不一一贅述了坤邪,通過一個(gè)簡(jiǎn)單的示例來說明,可能有不太符合的地罚缕,但是萬(wàn)變理解其宗就好艇纺。
  • 首先:http協(xié)議請(qǐng)求方式: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請(qǐng)求查看數(shù)據(jù):
127.0.0.1:8000/books 
返回所有數(shù)據(jù)列表 :[{}, {}, {}]

GET請(qǐng)求查看單條數(shù)據(jù):
127.0.0.1:8000/books/1 
返回查看的單條數(shù)據(jù){}

POST請(qǐng)求添加數(shù)據(jù):
127.0.0.1:8000/books 
返回添加數(shù)據(jù) :{}

PUT請(qǐng)求更新pk = 1的數(shù)據(jù):
127.0.0.1:8000/books/1 
返回更新后的數(shù)據(jù): {}

Delete請(qǐng)求刪除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猴娩,讓前端的人去請(qǐng)求這個(gè)url去獲取數(shù)據(jù),在頁(yè)面上顯示出來。這樣也就達(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) 分頁(yè)組件
  • (9) 響應(yīng)器組件
  • (10) url注冊(cè)器

五|1 - APIView:

APIView的源碼執(zhí)行可以參考DjangoCBV的源碼執(zhí)行邏輯

一張圖了解一下APIView的源碼執(zhí)行流程吧:
6_副本.png

五|2- 解析器組件

對(duì)請(qǐng)求的數(shù)據(jù)進(jìn)行解析:是針對(duì)請(qǐng)求體進(jìn)行解析的仓坞。表示服務(wù)器可以解析的數(shù)據(jù)格式的種類

先來看Django中的發(fā)送請(qǐng)求:

- view.py中post請(qǐng)求的執(zhí)行體:
2.png
- 如果是這樣的格式發(fā)送的數(shù)據(jù)背零,在POST里面有值

Content-Type: application/url-encoding..... //數(shù)據(jù)格式
request.body # 請(qǐng)求體中的原生數(shù)據(jù)
request.POST

1.png
- 如果是發(fā)送的json的格式,在POST里面是沒有值的无埃,在body里面有值徙瓶,可通過decode,然后loads取值

Content-Type: application/json..... //數(shù)據(jù)格式
request.body # 請(qǐng)求體中的原生數(shù)據(jù)
request.POST

3.png

這種情況下每次都要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ā)送請(qǐng)求:(和Django的對(duì)比發(fā)現(xiàn)不同)

- view.py中post請(qǐng)求的執(zhí)行體:
4.png
- 如果是這樣的格式發(fā)送的數(shù)據(jù),在POST里面有值

Content-Type: application/url-encoding..... //數(shù)據(jù)格式
request.body # 請(qǐng)求體中的原生數(shù)據(jù)
request.POST
request.data #reqest.data是APIView重裝request才有的壹若,reqest.data取值的時(shí)候才執(zhí)行解析器組件

5.png

- 如果是發(fā)送的json的格式嗅钻,在POST里面是沒有值的,在body里面有值店展,可通過decode,然后loads取值

Content-Type: application/json..... //數(shù)據(jù)格式
request.body # 請(qǐng)求體中的原生數(shù)據(jù)
request.POST
request.data #reqest.data是APIView重裝request才有的养篓,reqest.data取值的時(shí)候才執(zhí)行解析器組件

6.png

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

解析器源碼執(zhí)行流程.jpg

五|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建立一對(duì)多的關(guān)系,外鍵字段建立在多的一方
    publish = models.ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE)
    # 與Author表建立多對(duì)多的關(guān)系,ManyToManyField可以建在兩個(gè)模型中的任意一個(gè)壁查,自動(dòng)創(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)语御、錯(cuò)誤提示等附加功能

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ù)庫(kù)沒有實(shí)質(zhì)上的聯(lián)系,所以post請(qǐng)求時(shí)不能直接保存到數(shù)據(jù)庫(kù)

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()
    # 一對(duì)多字段席怪,可以通過source參數(shù)取出想要的關(guān)聯(lián)對(duì)象的任意字段
    publish_name = serializers.CharField(source="publish.name",read_only=True)
    publish_city = serializers.CharField(source="publish.city",read_only=True)
    # 多對(duì)多字段应闯,可以通過source參數(shù)取出所有關(guān)聯(lián)對(duì)象queryset集合,幾乎沒用
    # authors = serializers.CharField(max_length=32, source="authors.all",read_only=True)
    # 多對(duì)多字段挂捻,固定的書寫格式
    authors = serializers.SerializerMethodField(read_only=True)
    def get_authors(self, obj):  # 函數(shù)命名必須是get_field形式碉纺,obj為當(dāng)前字段對(duì)象
        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)  # 序列化錯(cuò)誤信息

- 基于DRF ( Django RestFramework ) ModelSerializer 的接口設(shè)計(jì)

DRF ( Django RestFramework ) Serializer的序列化方式可以類比Django的ModelForm組件的使用
當(dāng)涉及到一對(duì)多或者多對(duì)多字段時(shí),我們可以通過自定制操作來獲得我們想要的數(shù)據(jù)形式,
更多更細(xì)相關(guān)序列化內(nèi)容請(qǐng)看:https://www.cnblogs.com/pyspark/p/8607801.html

class BooklistSerializer(serializers.ModelSerializer):

    //serializers.ChoiceField字段也可以通過source="get_字段名_display"的方式取出對(duì)應(yīng)數(shù)字的中文簡(jiǎn)介
    //一對(duì)多字段骨田,可以通過source參數(shù)取出想要的關(guān)聯(lián)對(duì)象的任意字段
    //一對(duì)多字段耿导,需要添加read_only=True參數(shù),這個(gè)參數(shù)在post請(qǐng)求時(shí)有用

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

    // 多對(duì)多字段态贤,固定的書寫格式
    // 函數(shù)命名必須是get_field形式舱呻,obj為當(dāng)前字段對(duì)象

    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請(qǐng)求時(shí)不僅僅是序列化了,還需要驗(yàn)證悠汽、保存等箱吕,必須在實(shí)例化時(shí)加上data
        //post發(fā)送的是添加請(qǐng)求,單個(gè)對(duì)象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)         // 序列化錯(cuò)誤信息

強(qiáng)調(diào):API的設(shè)計(jì)符合RESTful規(guī)范(請(qǐng)求方式茬高、url設(shè)計(jì)、返回?cái)?shù)據(jù))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末假抄,一起剝皮案震驚了整個(gè)濱河市怎栽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宿饱,老刑警劉巖婚瓜,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異刑棵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)愚铡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門蛉签,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沥寥,你說我怎么就攤上這事碍舍。” “怎么了邑雅?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵片橡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我淮野,道長(zhǎng)捧书,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任骤星,我火速辦了婚禮经瓷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘洞难。我一直安慰自己舆吮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著色冀,像睡著了一般潭袱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锋恬,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天屯换,我揣著相機(jī)與錄音,去河邊找鬼伶氢。 笑死趟径,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的癣防。 我是一名探鬼主播蜗巧,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蕾盯!你這毒婦竟也來了幕屹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤级遭,失蹤者是張志新(化名)和其女友劉穎望拖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挫鸽,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡说敏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丢郊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盔沫。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖枫匾,靈堂內(nèi)的尸體忽然破棺而出架诞,到底是詐尸還是另有隱情,我是刑警寧澤干茉,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布谴忧,位于F島的核電站,受9級(jí)特大地震影響角虫,放射性物質(zhì)發(fā)生泄漏沾谓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一戳鹅、第九天 我趴在偏房一處隱蔽的房頂上張望搏屑。 院中可真熱鬧,春花似錦粉楚、人聲如沸辣恋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)伟骨。三九已至饮潦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間携狭,已是汗流浹背继蜡。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逛腿,地道東北人稀并。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像单默,于是被迫代替她去往敵國(guó)和親碘举。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 版權(quán): https://github.com/haiiiiiyun/awesome-django-cn Aweso...
    若與閱讀 23,109評(píng)論 3 241
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理搁廓,服務(wù)發(fā)現(xiàn)引颈,斷路器,智...
    卡卡羅2017閱讀 134,693評(píng)論 18 139
  • Refer to: www.threemeal.com/blog/12/ 中間件 中間件是一個(gè)鉤子框架境蜕,它們可以介...
    蘭山小亭閱讀 16,504評(píng)論 9 165
  • Django: csrf防御機(jī)制 csrf攻擊過程 1.用戶C打開瀏覽器蝙场,訪問受信任網(wǎng)站A,輸入用戶名和密碼請(qǐng)求登...
    lijun_m閱讀 1,062評(píng)論 0 0
  • 本文提到最好單身的幾種情況粱年,并不是干涉你的自由售滤,當(dāng)然也并非鼓勵(lì)你單身。正如評(píng)論遺棄小屋文章的一位朋友的情況台诗,自顧不...
    遺棄小屋閱讀 478評(píng)論 0 1