drf之restful規范


一 Web應用模式

在開發Web應用中,有兩種應用模式:

1.1 前后端不分離

前后端不分離

1.2 前后端分離

前后端分離

二 API接口

為了在團隊內部形成共識、防止個人習慣差異引起的混亂,我們需要找到一種大家都覺得很好的接口實現規范,而且這種規范能夠讓后端寫的接口,用途一目了然,減少雙方之間的合作成本。

通過網絡,規定了前后台信息交互規則的url鏈接,也就是前后台信息交互的媒介

Web API接口和一般的url鏈接還是有區別的,Web API接口簡單概括有下面四大特點

  • url:長得像返回數據的url鏈接

  • 請求方式:get、post、put、patch、delete

    • 采用get方式請求上方接口
  • 請求參數:json或xml格式的key-value類型數據

    • ak:6E823f587c95f0148c19993539b99295
    • region:上海
    • query:肯德基
    • output:json
  • 響應結果:json或xml格式的數據

    • 上方請求參數的output參數值決定了響應數據的格式

    • 數據

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      # xml格式
      https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295&region=%E4%B8%8A%E6%B5%B7&query=%E8%82%AF%E5%BE%B7%E5%9F%BA&output=xml
      #json格式
      https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295&region=%E4%B8%8A%E6%B5%B7&query=%E8%82%AF%E5%BE%B7%E5%9F%BA&output=json
      {
      "status":0,
      "message":"ok",
      "results":[
      {
      "name":"肯德基(羅餐廳)",
      "location":{
      "lat":31.415354,
      "lng":121.357339
      },
      "address":"月羅路2380號",
      "province":"上海市",
      "city":"上海市",
      "area":"寶山區",
      "street_id":"339ed41ae1d6dc320a5cb37c",
      "telephone":"(021)56761006",
      "detail":1,
      "uid":"339ed41ae1d6dc320a5cb37c"
      }
      ...
      ]
      }

三 接口測試工具:Postman

Postman是一款接口調試工具,是一款免費的可視化軟件,同時支持各種操作系統平台,是測試接口的首選工具。

Postman可以直接從官網:https://www.getpostman.com/downloads/下載獲得,然后進行傻瓜式安裝。

  • 工作面板

img

  • 簡易的get請求

img

  • 簡易的post請求

img

  • 案例:請求百度地圖接口

img

四 RESTful API規范

restful

REST全稱是Representational State Transfer,中文意思是表述(編者注:通常譯為表征性狀態轉移)。 它首次出現在2000年Roy Fielding的博士論文中。

RESTful是一種定義Web API接口的設計風格,尤其適用於前后端分離的應用模式中。

這種風格的理念認為后端開發任務就是提供數據的,對外提供的是數據資源的訪問接口,所以在定義接口時,客戶端訪問的URL路徑就表示這種要操作的數據資源。

事實上,我們可以使用任何一個框架都可以實現符合restful規范的API接口。

4.1 數據的安全保障

  • url鏈接一般都采用https協議進行傳輸

    注:采用https協議,可以提高數據交互過程中的安全性

4.2 接口特征表現

4.3 多數據版本共存

4.4 數據即是資源,均使用名詞(可復數)

4.5 資源操作由請求方式決定(method)

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

4.7 響應狀態碼

4.7.1 正常響應

  • 響應狀態碼2xx
    • 200:常規請求
    • 201:創建成功

4.7.2 重定向響應

  • 響應狀態碼3xx
    • 301:永久重定向
    • 302:暫時重定向

4.7.3 客戶端異常

  • 響應狀態碼4xx
    • 403:請求無權限
    • 404:請求路徑不存在
    • 405:請求方法不存在

4.7.4 服務器異常

  • 響應狀態碼5xx
    • 500:服務器異常

4.8 錯誤處理,應返回錯誤信息,error當做key

1
2
3
{
error: "無權限操作"
}

4.9 返回結果,針對不同操作,服務器向用戶返回的結果應該符合以下規范

1
2
3
4
5
6
GET /collection:返回資源對象的列表(數組)
GET /collection/resource:返回單個資源對象
POST /collection:返回新生成的資源對象
PUT /collection/resource:返回完整的資源對象
PATCH /collection/resource:返回完整的資源對象
DELETE /collection/resource:返回一個空文檔

4.10 需要url請求的資源需要訪問資源的請求鏈接

1
2
3
4
5
6
7
8
9
10
11
12
# Hypermedia API,RESTful API最好做到Hypermedia,即返回結果中提供鏈接,連向其他API方法,使得用戶不查文檔,也知道下一步應該做什么
{
"status": 0,
"msg": "ok",
"results":[
{
"name":"肯德基(羅餐廳)",
"img": "https://image.baidu.com/kfc/001.png"
}
...
]
}

比較好的接口返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 響應數據要有狀態碼、狀態信息以及數據本身
{
"status": 0,
"msg": "ok",
"results":[
{
"name":"肯德基(羅餐廳)",
"location":{
"lat":31.415354,
"lng":121.357339
},
"address":"月羅路2380號",
"province":"上海市",
"city":"上海市",
"area":"寶山區",
"street_id":"339ed41ae1d6dc320a5cb37c",
"telephone":"(021)56761006",
"detail":1,
"uid":"339ed41ae1d6dc320a5cb37c"
}
...
]
}

四 序列化

api接口開發,最核心最常見的一個過程就是序列化,所謂序列化就是把數據轉換格式,序列化可以分兩個階段:

序列化: 把我們識別的數據轉換成指定的格式提供給別人。

例如:我們在django中獲取到的數據默認是模型對象,但是模型對象數據無法直接提供給前端或別的平台使用,所以我們需要把數據進行序列化,變成字符串或者json數據,提供給別人。

反序列化:把別人提供的數據轉換/還原成我們需要的格式。

例如:前端js提供過來的json數據,對於python而言就是字符串,我們需要進行反序列化換成模型類對象,這樣我們才能把數據保存到數據庫中。

五 Django Rest_Framework

核心思想: 縮減編寫api接口的代碼

Django REST framework是一個建立在Django基礎之上的Web 應用開發框架,可以快速的開發REST API接口應用。在REST framework中,提供了序列化器Serialzier的定義,可以幫助我們簡化序列化與反序列化的過程,不僅如此,還提供豐富的類視圖、擴展類、視圖集來簡化視圖的編寫工作。REST framework還提供了認證、權限、限流、過濾、分頁、接口文檔等功能支持。REST framework提供了一個API 的Web可視化界面來方便查看測試接口。

drf_logo

官方文檔:https://www.django-rest-framework.org/

github: https://github.com/encode/django-rest-framework/tree/master

特點

  • 提供了定義序列化器Serializer的方法,可以快速根據 Django ORM 或者其它庫自動序列化/反序列化;
  • 提供了豐富的類視圖、Mixin擴展類,簡化視圖的編寫;
  • 豐富的定制層級:函數視圖、類視圖、視圖集合到自動生成 API,滿足各種需要;
  • 多種身份認證和權限認證方式的支持;[jwt]
  • 內置了限流系統;
  • 直觀的 API web 界面;
  • 可擴展性,插件豐富

六 環境安裝與配置

DRF需要以下依賴:

  • Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
  • Django (1.10, 1.11, 2.0)

DRF是以Django擴展應用的方式提供的,所以我們可以直接利用已有的Django環境而無需從新創建。(若沒有Django環境,需要先創建環境安裝Django)

6.1 安裝DRF

前提是已經安裝了django,建議安裝在虛擬環境

1
2
3
4
5
# mkvirtualenv drfdemo -p python3
# pip install django

pip install djangorestframework
pip install pymysql

6.1.1 創建django項目

1
2
cd ~/Desktop
django-admin startproject drfdemo

使用pycharm打開項目,設置虛擬環境的解析器,並修改manage.py中的后綴參數。

6.2 添加rest_framework應用

settings.pyINSTALLED_APPS中添加’rest_framework’。

1
2
3
4
INSTALLED_APPS = [
...
'rest_framework',
]

接下來就可以使用DRF提供的功能進行api接口開發了。在項目中如果使用rest_framework框架實現API接口,主要有以下三個步驟:

  • 將請求的數據(如JSON格式)轉換為模型類對象
  • 操作數據庫
  • 將模型類對象轉換為響應的數據(如JSON格式)

接下來,我們快速體驗下四天后我們學習完成drf以后的開發代碼。接下來代碼不需要理解,看步驟。

6.3 體驗drf完全簡寫代碼的過程(了解)

6.3.1. 創建模型操作類

1
2
3
4
5
6
7
8
9
10
11
12
class Student(models.Model):
# 模型字段
name = models.CharField(max_length=100,verbose_name="姓名")
sex = models.BooleanField(default=1,verbose_name="性別")
age = models.IntegerField(verbose_name="年齡")
class_null = models.CharField(max_length=5,verbose_name="班級編號")
description = models.TextField(max_length=1000,verbose_name="個性簽名")

classMeta:
db_table="tb_student"
verbose_name = "學生"
verbose_name_plural = verbose_name

為了方便測試,所以我們可以先創建一個數據庫。

1
create database students charset=utf8;
6.3.1.1 執行數據遷移

把students子應用添加到INSTALL_APPS中

1557023819604

初始化數據庫連接

1
2
安裝pymysql
pip install pymysql

主引用中__init__.py設置使用pymysql作為數據庫驅動

1
2
3
import pymysql

pymysql.install_as_MySQLdb()

settings.py配置文件中設置mysql的賬號密碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# },
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "students",
"HOST": "127.0.0.1",
"PORT": 3306,
"USER": "root",
"PASSWORD":"123",
},
}

終端下,執行數據遷移。

1
2
python manage.py makemigrations
python manage.py migrate

錯誤列表

1
# 執行數據遷移 python manage.py makemigrations 報錯如下:

1557024349366

解決方案:

1
注釋掉 backends/mysql/base.py中的3536行代碼。

1557025991751

1
# 執行數據遷移發生以下錯誤:

1557026113769

解決方法:

backends/mysql/operations.py146行里面新增一個行代碼:

1557026224431

6.3.2. 創建序列化器

例如,在django項目中創建學生子應用。

1
python manage.py startapp students

在syudents應用目錄中新建serializers.py用於保存該應用的序列化器。

創建一個StudentModelSerializer用於序列化與反序列化。

1
2
3
4
5
# 創建序列化器類,回頭會在試圖中被調用
classStudentModelSerializer(serializers.ModelSerializer):
classMeta:
model = Student
fields = "__all__"
  • model 指明該序列化器處理的數據字段從模型類BookInfo參考生成
  • fields 指明該序列化器包含模型類中的哪些字段,’all‘指明包含所有字段

6.3.3. 編寫視圖

在students應用的views.py中創建視圖StudentViewSet,這是一個視圖集合。

1
2
3
4
5
6
7
from rest_framework.viewsets import ModelViewSet
from .models import Student
from .serializers import StudentModelSerializer
# Create your views here.
classStudentViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
  • queryset 指明該視圖集在查詢數據時使用的查詢集
  • serializer_class 指明該視圖在進行序列化或反序列化時使用的序列化器

6.3.4. 定義路由

在students應用的urls.py中定義路由信息。

1
2
3
4
5
6
7
8
9
10
from . import views
from rest_framework.routers import DefaultRouter

# 路由列表
urlpatterns = []

router = DefaultRouter() # 可以處理視圖的路由器
router.register('students', views.StudentViewSet) # 向路由器中注冊視圖集

urlpatterns += router.urls # 將路由器中的所以路由信息追到到django的路由列表中

最后把students子應用中的路由文件加載到總路由文件中.

1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
path('admin/', admin.site.urls),
path("stu/",include("students.urls")),
]

6.3.5. 運行測試

運行當前程序(與運行Django一樣)

1
python manage.py runserver

在瀏覽器中輸入網址127.0.0.1:8000,可以看到DRF提供的API Web瀏覽頁面:

1557027948031

1)點擊鏈接127.0.0.1:8000/stu/students 可以訪問獲取所有數據的接口,呈現如下頁面:

1557027878963

2)在頁面底下表單部分填寫學生信息,可以訪問添加新學生的接口,保存學生信息:

1557027999506

點擊POST后,返回如下頁面信息:

1557028072470

3)在瀏覽器中輸入網址127.0.0.1:8000/stu/students/5/,可以訪問獲取單一學生信息的接口(id為5的學生),呈現如下頁面:

1557028115925

4)在頁面底部表單中填寫學生信息,可以訪問修改學生的接口

1557028168350

點擊PUT,返回如下頁面信息:

1557028208243

5)點擊DELETE按鈕,可以訪問刪除學生的接口

1557028242637

返回,如下頁面:

1557028266190

七 CBV源碼分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 視圖層
from django.shortcuts import render, HttpResponse
from django.views import View
classCBVTest(View):
# 通過調度(dispatch)分發請求
defdispatch(self, request, *args, **kwargs):
pass
super().dispatch(request, *args, **kwargs)
pass

defget(self, request):
return render(request, 'cbv.html')

defpost(self, request):
return HttpResponse('cbv post method')
1
2
3
4
5
6
<!-- 模板層 -->
<formaction="/cbv/"method="post">
{% csrf_token %}
<inputtype="text"name="usr">
<buttontype="submit">提交</button>
</form>
1
2
3
4
5
# 路由層
from app import views
urlpatterns = [
url(r'^cbv/', views.CBVTest.as_view()),
]

八 drf基本使用及request源碼分析

8.1 APIView的使用

1
2
3
# 1)安裝drf:pip3 install djangorestframework
# 2)settings.py注冊app:INSTALLED_APPS = [..., 'rest_framework']
# 3)基於cbv完成滿足RSSTful規范的接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 視圖層
from rest_framework.views import APIView
from rest_framework.response import Response
user_list = [{'id': 1, 'name': 'Bob'}, {'id': 2, 'name': 'Tom'}]
classUsers(APIView):
defget(self, request, *args, **kwargs):
return Response({
'status': 0,
'msg': 'ok',
'results': user_list
})
defpost(self, request, *args, **kwargs):
# request對formdata,urlencoded,json三個格式參數均能解析
name = request.data.get('name')
id = len(user_list) + 1
user = {'id': id, 'name': name}
user_list.append(user)
return Response({
'status': '0',
'msg': 'ok',
'results': user
})
1
2
3
4
5
# 路由層
from app import views
urlpatterns = [
url(r'^users/', views.Users.as_view()),
]

8.2 APIView和Request對象源碼分析

8.2.1 APIView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# as_view()
# 核心走了父類as_view
view = super(APIView, cls).as_view(**initkwargs)
# 返回的是局部禁用csrf認證的view視圖函數
return csrf_exempt(view)

# dispatch(self, request, *args, **kwargs)
# 二次封裝request對象
request = self.initialize_request(request, *args, **kwargs)
# 自定義request規則
self.initial(request, *args, **kwargs)

# initialize_request(self, request, *args, **kwargs)
# 原生request封裝在request._request

# initial(self, request, *args, **kwargs)
# 認證
self.perform_authentication(request)
# 權限
self.check_permissions(request)
# 頻率
self.check_throttles(request)

8.2.2 Request對象

image-20200705223439308


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM