DRF之簡介以及序列化操做

1. Web應用模式.

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

  1. 先後端不分離前端

 

2.先後端分離python

2. api接口

爲了在團隊內部造成共識、防止我的習慣差別引發的混亂,咱們須要找到一種你們都以爲很好的接口實現規範,並且這種規範可以讓後端寫的接口,用途一目瞭然,減小雙方之間的合做成本。git

目前市面上大部分公司開發人員使用的接口服務架構主要有:restful、rpc。github

rpc: 翻譯成中文:遠程過程調用[遠程服務調用].web

http://www.lufei.com/api數據庫

post請求django

action=get_all_student&params=301&sex=1json

 

接口多了,對應函數名和參數就多了,前端在請求api接口時,就會比較難找.容易出現重複的接口後端

restful: 翻譯成中文: 資源狀態轉換.把後端全部的數據/文件都當作資源.那麼接口請求數據,本質上來講就是對資源的操做了.

web項目中操做資源,無非就是增刪查改.因此要求在地址欄中聲明要操做的資源是什麼,而後經過http請求動詞來講明對資源進行哪種操做.

  POST http://www.lufei.com/api/students/ 添加數據

  GET http://www.lufei.com/api/students/ 獲取全部學生

 

3. RESTful API規範

REST全稱是Representational State Transfer,中文意思是表述(編者注:一般譯爲表徵)性狀態轉移。 它首次出如今2000年Roy Fielding的博士論文中。

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

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

而對於數據資源分別使用POST、DELETE、GET、UPDATE等請求動做來表達對數據的增刪查改。

| 請求方法 | 請求地址 | 後端操做 |
| -------- | ----------- | ----------------- |
| GET | /students | 獲取全部學生 |
| POST | /students | 增長學生 |
| GET | /students/1 | 獲取編號爲1的學生 |
| PUT | /students/1 | 修改編號爲1的學生 |
| DELETE | /students/1 | 刪除編號爲1的學生 |

 

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

參考文檔:http://www.runoob.com/w3cnote/restful-architecture.html

 

4. 序列化

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

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

例如:咱們在django中獲取到的數據默認是模型對象,可是模型對象數據沒法直接提供給前端或別的平臺使用,因此咱們須要把數據進行序列化,變成字符串或者json數據,提供給別人。

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

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

 

5. Django Rest_Framework

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

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

中文文檔:https://q1mi.github.io/Django-REST-framework-documentation/#django-rest-framework

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

特色

  • 提供了定義序列化器Serializer的方法,能夠快速根據 Django ORM 或者其它庫自動序列化/反序列化;

  • 提供了豐富的類視圖、Mixin擴展類,簡化視圖的編寫;

  • 豐富的定製層級:函數視圖、類視圖、視圖集合到自動生成 API,知足各類須要;

  • 多種身份認證和權限認證方式的支持;[jwt]

  • 內置了限流系統;

  • 直觀的 API web 界面;

  • 可擴展性,插件豐富

6. 環境安裝與配置

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

pip install djangorestframework

6.2 添加rest_framework應用

  在settings.pyINSTALLED_APPS中添加'rest_framework'。

INSTALLED_APPS = [
    ...
    'rest_framework',
]

接下來就可使用DRF進行開發了。在項目中若是使用rest_framework框架實現API接口,主要有如下三個步驟:

  • 將請求的數據(如JSON格式)轉換爲模型類對象

  • 操做數據庫

  • 將模型類對象轉換爲響應的數據(如JSON格式)

 

建立django項目:

  注意,最好使用cmd窗口命令建立原生django項目,不要用pycharm自帶的工具建立,避免pycharm自身增長的一些配置,防止在項目合做開發時遇到合併代碼時出現問題;

 

django-admin.py startproject mysite

 

一個完整的使用模型序列化的示例:

url:

from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include("demo1.urls")), ]
View Code

demo1 url:

from rest_framework.routers import DefaultRouter from .views import BookInfoAPIView urlpatterns = [] # 建立路由對象
routers = DefaultRouter() # 經過路由對象對視圖類進行路由生成
routers.register("books",BookInfoAPIView) urlpatterns+=routers.urls
View Code

demo1 view試圖:

from rest_framework.viewsets import ModelViewSet from demo1.models import BookInfo from .serializers import BookInfoSerializer # Create your views here.
class BookInfoAPIView(ModelViewSet): # 當前視圖類全部方法使用得數據結果集是誰?
    queryset = BookInfo.objects.all() # 當前視圖類使用序列化器類是誰
    serializer_class = BookInfoSerializer
View Code

models:

from django.db import models # Create your models here.

# Create your models here. #定義圖書模型類BookInfo
class BookInfo(models.Model): btitle = models.CharField(max_length=20, verbose_name='圖書標題') bpub_date = models.DateField(verbose_name='出版時間') bread = models.IntegerField(default=0, verbose_name='閱讀量') bcomment = models.IntegerField(default=0, verbose_name='評論量') is_delete = models.BooleanField(default=False, verbose_name='邏輯刪除') class Meta: db_table = 'tb_books'  # 指明數據庫表名
        verbose_name = '圖書'  # 在admin站點中顯示的名稱
        verbose_name_plural = verbose_name  # 顯示的複數名稱

    def __str__(self): """定義每一個數據對象的顯示信息"""
        return "圖書:《"+self.btitle+""


#定義英雄模型類HeroInfo
class HeroInfo(models.Model): GENDER_CHOICES = ( (0, ''), (1, '') ) hname = models.CharField(max_length=20, verbose_name='名稱') hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性別') hcomment = models.CharField(max_length=200, null=True, verbose_name='技能描述') hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='所屬圖書')  # 外鍵
    is_delete = models.BooleanField(default=False, verbose_name='邏輯刪除') class Meta: db_table = 'tb_heros' verbose_name = '英雄' verbose_name_plural = verbose_name def __str__(self): return self.hname
View Code

運行項目後,可進行增刪改查操做:

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

  點擊連接127.0.0.1:8000/books/ 能夠訪問獲取全部數據的接口(查看全部,添加)

  在瀏覽器中輸入網址127.0.0.1:8000/books/d+/,能夠訪問獲取單一圖書信息的接口(id爲d+的圖書) (刪除.修改)

 

序列化與反序列化(不包含DRF的視圖操做):用法和forms組件很相像

 

定義序列化器

 

Django REST framework中的Serializer使用類來定義,須繼承自rest_framework.serializers.Serializer。

 

例如,咱們已有了一個數據庫模型類BookInfo

class BookInfo(models.Model): btitle = models.CharField(max_length=20, verbose_name='名稱') bpub_date = models.DateField(verbose_name='發佈日期', null=True) bread = models.IntegerField(default=0, verbose_name='閱讀量') bcomment = models.IntegerField(default=0, verbose_name='評論量') image = models.ImageField(upload_to='booktest', verbose_name='圖片', null=True)
View Code

咱們想爲這個模型類提供一個序列化器,能夠定義以下:

class BookInfoSerializer(serializers.Serializer): """圖書數據序列化器""" id = serializers.IntegerField(label='ID', read_only=True) btitle = serializers.CharField(label='名稱', max_length=20) bpub_date = serializers.DateField(label='發佈日期', required=False) bread = serializers.IntegerField(label='閱讀量', required=False) bcomment = serializers.IntegerField(label='評論量', required=False) image = serializers.ImageField(label='圖片', required=False)
View Code

注意:serializer不是隻能爲數據庫模型類定義,也能夠爲非數據庫模型類的數據定義。serializer是獨立於數據庫以外的存在。

 

建立Serializer對象

定義好Serializer類後,就能夠建立Serializer對象了。

Serializer的構造方法爲:

Serializer(instance=None, data=empty, **kwarg)

說明:

1)用於序列化時,將模型類對象傳入instance參數

2)用於反序列化時,將要被反序列化的數據傳入data參數

3)除了instance和data參數外,在構造Serializer對象時,還可經過context參數額外添加數據,如

serializer = AccountSerializer(account, context={'request': request})

經過context參數附加的數據,能夠經過Serializer對象的context屬性獲取。

 

  1. 使用序列化器的時候必定要注意,序列化器聲明瞭之後,不會自動執行,須要咱們在視圖中進行調用才能夠。

  2. 序列化器沒法直接接收數據,須要咱們在視圖中建立序列化器對象時把使用的數據傳遞過來。

  3. 序列化器的字段聲明相似於咱們前面使用過的表單系統。

  4. 開發restful api時,序列化器會幫咱們把模型數據轉換成字典.

  5. drf提供的視圖會幫咱們把字典轉換成json,或者把客戶端發送過來的數據轉換字典.

 

序列化器的使用

序列化器的使用分兩個階段:

  1. 在客戶端請求時,使用序列化器能夠完成對數據的反序列化。

  2. 在服務器響應時,使用序列化器能夠完成對數據的序列化。

 

序列化demo:

drf-url:

from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include("demo1.urls")), path('ser/', include("ser.urls")), ]
View Code

ser-url:

from django.urls import path, re_path from . import views urlpatterns = [ path("books/",views.BookInfoView.as_view()), ]
View Code

views:

from django.http import JsonResponse from django.shortcuts import render from django.views import View from demo1.models import BookInfo from .serializers import BookInfoSerializer class BookInfoView(View): def get(self,request): # 操做數據庫
        books = BookInfo.objects.all() # 建立序列化器對象
        # 參數1: instance=要序列化的模型數據
        # 參數2: data=要反序列化器的字典數據
        # 參數3: many= 是否要序列化多個模型數據,多條數據many=True,默認一條數據
        # 參數4: context=序列化器使用的上下文,字典類型數據,能夠經過context把視圖中的數據,傳遞給序列化器內部使用
        serializer = BookInfoSerializer(instance=books, many=True) # 經過 serializer.data 獲取序列化完成之後的數據
        print(serializer.data) # 返回數據
        return JsonResponse(serializer.data, safe=False)
View Code

serialize:

############################################################################################################################### # 1. 序列化器的序列化階段使用 ###############################################################################################################################
from rest_framework import serializers class BookInfoSerializer(serializers.Serializer): # # 自定義要序列化的字段
    id = serializers.IntegerField(label="主鍵ID",read_only=True) btitle=serializers.CharField(label="圖書標題") bpub_date = serializers.DateField(label="出版日期") bread=serializers.IntegerField(label="閱讀量") bcomment=serializers.IntegerField(label="評論量") is_delete=serializers.BooleanField(label="邏輯刪除")
View Code

 

反序列化定義:

  序列化的表格能夠和反序列化的表公用,並且反序列化的表更增強大,由於還能驗證數據,因此通常只保留反序列化的序列化表,不過對於一些只讀的字段,可添加read_only 字段選項來避免

  使用序列化器進行反序列化時,須要對數據進行驗證後,才能獲取驗證成功的數據或保存成模型類對象。

  在獲取反序列化的數據前,必須調用is_valid()方法進行驗證,驗證成功返回True,不然返回False。

  驗證失敗,能夠經過序列化器對象的errors屬性獲取錯誤信息,返回字典,包含了字段和字段的錯誤。若是是非字段錯誤,能夠經過修改REST framework配置中的NON_FIELD_ERRORS_KEY來控制錯誤字典中的鍵名。

  驗證成功,能夠經過序列化器對象的validated_data屬性獲取數據。

  在定義序列化器時,指明每一個字段的序列化類型和選項參數,自己就是一種驗證行爲。

 

反序列化demo:

drf-url:

from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), # path('api/', include("demo1.urls")),
    path('ser/', include("ser.urls")), ]
View Code

ser-urls:

from django.urls import path, re_path from . import views urlpatterns = [ path("books2/", views.BookInfo2View.as_view()), re_path("books2/(?P<pk>\d+)/", views.BookInfo2View.as_view()), ]
View Code

views:

from django.views import View from django.http import JsonResponse from django.http import QueryDict from .serializers import BookInfo2Serializer from demo1.models import BookInfo ############################################################################################################################### # 2 序列化器的反序列化階段使用 # 主要用戶驗證數據和字典數據轉換成模型 # 爲了保證測試順利進行,咱們在settings.py中關閉 csrf的中間件 # 'django.middleware.csrf.CsrfViewMiddleware', ###############################################################################################################################

class BookInfo2View(View): def get(self,request): # 操做數據庫
        books = BookInfo.objects.all() # 建立序列化器對象
        # 參數1: instance=要序列化的模型數據
        # 參數2: data=要反序列化器的字典數據
        # 參數3: many= 是否要序列化多個模型數據,多條數據many=True,默認一條數據
        # 參數4: context=序列化器使用的上下文,字典類型數據,能夠經過context把視圖中的數據,傳遞給序列化器內部使用
        serializer = BookInfo2Serializer(instance=books, many=True) # 經過 serializer.data 獲取序列化完成之後的數據
        print(serializer.data) # 返回數據
        return JsonResponse(serializer.data, safe=False) def post(self, request): """添加一本圖書"""
        # 接受數據
        data = request.POST # 反序列化
        serializer = BookInfo2Serializer(data=data) # 1. 驗證數據
        # raise_exception=True 把驗證的錯誤信息返回給客戶端,同時阻止程序繼續往下執行
        serializer.is_valid(raise_exception=True) # is_valid調用驗證方式: 字段選項validators->自定義驗證方法[單字段]->自定義驗證方法[多字段]
        # 驗證成功後的數據
        # print(serializer.validated_data)

        # 2. 轉換數據成模型,同步到數據庫中
        result = serializer.save()  # save會自動調用序列化器類裏面聲明的create/update方法,返回值是當前新增/更新的模型對象

        # 響應數據
        return JsonResponse(serializer.data) def put(self,request,pk): """更新一個圖書"""
        # 根據id主鍵獲取指定圖書信息
        instance=BookInfo.objects.get(pk=pk) data = QueryDict(request.body) # 使用序列化器完成驗證和反序列化過程
        # partial=True 接下里在反序列化中容許部分數據更新
        serializer = BookInfo2Serializer(instance=instance,data=data,partial=True) serializer.is_valid(raise_exception=True) # save之因此能夠自動識別,何時執行create ,何時執行update
        # 主要是看建立序列化器對象時,是否有傳入instance參數,
        # 有instance參數,則save會調用序列化器內部的update方法
        # 沒有instance參數,則save會調用序列化器內部的create方法
        result = serializer.save() return JsonResponse(serializer.data)
View Code

serialize:

############################################################################################################################### # 2 序列化器的反序列化階段使用 # 主要用戶驗證數據和字典數據轉換成模型 ###############################################################################################################################
from rest_framework import serializers from demo1.models import BookInfo # 自定義驗證字段選項函數,不多用
def check_btitle(data): if data=="西廂記": raise serializers.ValidationError("西廂記也是禁書~") # 必定要返回數據
    return data class BookInfo2Serializer(serializers.Serializer): # 自定義要反序列化的字段
    id = serializers.IntegerField(label="主鍵ID",read_only=True) btitle = serializers.CharField(label="標題",required=True,min_length=1,max_length=20,validators=[check_btitle])  #經過validators=[check_btitle,]調用自定義選項函數
    bpub_date=serializers.DateField(label="出版日期") bread=serializers.IntegerField(label="閱讀量",min_value=0) bcomment=serializers.IntegerField(label="評論量",default=0) # required=False 反序列化時, 當前字段能夠不填
    is_delete=serializers.BooleanField(label="邏輯刪除") # 自定義驗證方法[驗證單個字段,能夠有多個方法]
    #寫法必須是 def validate_<字段名>(self,data): # data當前字段對應的值
    def validate_btitle(self,data): # 例如,圖書名不能是紅樓夢
        if data=="紅樓夢": # 拋出錯誤
            raise serializers.ValidationError("紅樓夢是禁書~") # 驗證方法中,把數據值必須返回給字段,不然字段值爲空
        return data # 自定義驗證方法[驗證多個或者全部字段,只能出現一次] 寫法必須是validate(self,data)
    def validate(self,data): # data 這個是全部字段的內容,字典類型
        bread = data.get("bread") bcomment = data.get("bcomment") if bread>=bcomment: return data raise serializers.ValidationError("閱讀量小於評論量,數據太假了") def create(self,validated_data): """ 保存數據,把字典轉換成模型 validated_data 客戶端提交過來,並通過驗證的數據 """ instance = BookInfo.objects.create( btitle = validated_data.get("btitle"), bread = validated_data.get("bread"), bcomment = validated_data.get("bcomment"), bpub_date = validated_data.get("bpub_date"), is_delete = validated_data.get("is_delete"), ) #返回模型對象
        return instance def update(self,instance,validated_data): """更新數據 instance 本次更新操做的模型對象 validated_data 客戶端提交過來,並通過驗證的數據 """ instance.btitle=validated_data.get('btitle') instance.bread=validated_data.get('bread') instance.bcomment=validated_data.get('bcomment') instance.bpub_date=validated_data.get('bpub_date') instance.is_delete=validated_data.get('is_delete') # 調用ORM的保存更新操做
 instance.save() # 返回模型對象
        return instance ######################################################################################
View Code

 

模型類序列化:至關於modelform組件....用法等

  若是咱們想要使用序列化器對應的是Django的模型類,DRF爲咱們提供了ModelSerializer模型類序列化器來幫助咱們快速建立一個Serializer類。

ModelSerializer與常規的Serializer相同,但提供了:

  • 基於模型類自動生成一系列字段

  • 基於模型類自動爲Serializer生成validators,好比unique_together

  • 包含默認的create()和update()的實現

 

demo:

views:

############################################################################################################################### # 3 模型序列化器 # 1. 能夠幫咱們自動完成字段的聲明[主要是從模型中的字段聲明裏面提取過來] # 2. 模型序列化器也能夠幫咱們聲明瞭create和update方法的代碼 ###############################################################################################################################
from django.views import View from django.http import JsonResponse from .serializers import BookInfoModelSerializer class BookInfo3View(View): def post(self, request): data = request.POST serializer = BookInfoModelSerializer(data=data) serializer.is_valid(raise_exception=True) result = serializer.save() # 響應數據
        return JsonResponse(serializer.data) def put(self, request, pk): """更新一個圖書""" book = BookInfo.objects.get(pk=pk) # 獲取put提交的數據
        data = QueryDict(request.body) #容許部分更新partial=True
        serializer = BookInfoModelSerializer(instance=book, data=data, partial=True) serializer.is_valid(raise_exception=True) serializer.save() # 響應數據
        return JsonResponse(serializer.data)
View Code

serialize:

######################################################################################

from rest_framework import serializers from demo1.models import BookInfo class BookInfoModelSerializer(serializers.ModelSerializer): class Meta: model = BookInfo # fields = ["id", "btitle"]
        fields='__all__'
        # 能夠給模型序列化器裏面指定的字段設置限制選項
        extra_kwargs = { "bread": {"min_value": 0, "required": True}, } def validate_btitle(self,data): # 例如,圖書名不能是紅樓夢
        if data=="紅樓夢": # 拋出錯誤
            raise serializers.ValidationError("紅樓夢是禁書~") # 驗證方法中,把數據值必須返回給字段,不然字段值爲空
        return data # 自定義驗證方法[驗證多個或者全部字段,只能出現一次]
    def validate(self,data): # data 這個是全部字段的內容,字典類型
        bread = data.get("bread") bcomment = data.get("bcomment") if bread>=bcomment: return data raise serializers.ValidationError("閱讀量小於評論量,數據太假了")
View Code

 

 

補充一些參數:

1.經常使用字段類型

字段 字段構造方式
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正則字段,驗證正則模式 [a-zA-Z0-9-]+
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(format='hex_verbose') format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
IPAddressField IPAddressField(protocol='both', unpack_ipv4=False, **options)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位數 decimal_palces: 小數點位置
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField DurationField()
ChoiceField ChoiceField(choices) choices與Django的用法相同
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)

 

2.選項參數:

參數名稱 做用
max_length 最大長度
min_lenght 最小長度
allow_blank 是否容許爲空
trim_whitespace 是否截斷空白字符
max_value 最小值
min_value 最大值

 

3.通用參數:

參數名稱 說明
read_only 代表該字段僅用於序列化輸出,默認False
write_only 代表該字段僅用於反序列化輸入,默認False
required 代表該字段在反序列化時必須輸入,默認True
default 反序列化時使用的默認值
allow_null 代表該字段是否容許傳入None,默認False
validators 該字段使用的驗證器
error_messages 包含錯誤編號與錯誤信息的字典
label 用於HTML展現API頁面時,顯示的字段名稱
help_text 用於HTML展現API頁面時,顯示的字段幫助提示信息
相關文章
相關標籤/搜索