一: DRF web應用框架基礎,及序列化器的使用

---恢復內容開始---html

一: web 應用模式(有兩種)前端

1: 先後端不分離(前端從後端直接獲取數據)python

2: 先後端分離mysql

二: api 接口git

緣由一: 爲了在團隊內部造成共識、防止我的習慣差別引發的混亂,咱們須要找到一種你們都以爲很好的接口實現規範,
並且這種規範可以讓後端寫的接口,用途一目瞭然,減小雙方之間的合做成本。 目前市面上大部分公司開發人員使用的接口服務架構主要有:restful、rpc。
1: rpc: 翻譯成中文:遠程過程調用[遠程服務調用]. post請求 action=get_all_student&params=301&sex=1 緣由二: 接口多了,對應函數名和參數就多了,前端在請求api接口時,就會比較難找.容易出現重複的接口 2: restful: 翻譯成中文: 資源狀態轉換. 把後端全部的數據/文件都當作資源. 那麼接口請求數據,本質上來講就是對資源的操做了. web項目中操做資源,無非就是增刪查改.因此要求在地址欄中聲明要操做的資源是什麼,而後經過http請求動詞來講明對資源進行哪種操做. POST http://www.lufei.com/api/students/ 添加數據 GET http://www.lufei.com/api/students/ 獲取全部學生

三: RESTful API規範github

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.htmlweb

四: 序列化sql

api接口開發,最核心最多見的一個過程就是序列化,所謂序列化就是把**數據轉換格式**,序列化能夠分兩個階段:
1. 序列化: 把咱們識別的數據轉換成指定的格式提供給別人。
例如:咱們在django中獲取到的數據默認是模型對象,可是模型對象數據沒法直接提供給前端或別的平臺使用,因此咱們須要把數據進行序列化,變成字符串或者json數據,提供給別人。

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

五: Django Rest_Framework(DRF網絡框架)shell

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

執行流程:

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

Django REST framework是一個創建在Django基礎之上的Web 應用開發框架,能夠快速的開發REST API接口應用。在REST framework中,提供了序列化器Serialzier的定義,能夠幫助咱們簡化序列化與反序列化的過程,不只如此,還提供豐富的類視圖、擴展類、視圖集來簡化視圖的編寫工做。REST framework還提供了認證、權限、限流、過濾、分頁、接口文檔等功能支持。REST framework提供了一個API 的Web可視化界面來方便查看測試接口。
概述
- 提供了定義序列化器Serializer的方法,能夠快速根據 Django ORM 或者其它庫自動序列化/反序列化;
- 提供了豐富的類視圖、Mixin擴展類,簡化視圖的編寫;
- 豐富的定製層級:函數視圖、類視圖、視圖集合到自動生成 API,知足各類須要;
- 多種身份認證和權限認證方式的支持;[jwt]
- 內置了限流系統;
- 直觀的 API web 界面;
- 可擴展性,插件豐富
特色

六: 安裝及配置環境

1.部署環境

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)
1. 本地安裝django項目
django-admin startproject drf

2. 建立子應用目錄booktest,在項目根目錄下執行如下命令
python manage.py startapp booktest

建立一個數據庫,book
create database book charset=utf8;
grant all privileges on book.* to root@localhost identified by '123456';
flush privileges;

3. 配置數據庫信息
   3.1 在主應用drf目錄下的drf/__init__.py添加如下代碼:
   import pymysql
   pymysql.install_as_MySQLdb()
   
   3.2 在項目配置文件中,settings中修改數據連接信息。
   
   DATABASES = {
    # 'default': {
    #     'ENGINE': 'django.db.backends.sqlite3',
    #     'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    # }
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'drf',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    },
    }
新建項目及配置項目

2. 定義

  建立應用book_test,在book_test目錄下的models.py中定義模型類,建立模型表

from django.db import models

#定義圖書模型類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, 'female'),
        (1, 'male')
    )
    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
1) 數據庫表名
模型類若是未指明表名,Django默認以 小寫app應用名_小寫模型類名 爲數據庫表名。
可經過db_table 指明數據庫表名。
2) 關於主鍵
django會爲表建立自動增加的主鍵列,每一個模型只能有一個主鍵列,若是使用選項設置某屬性爲主鍵列後django不會再建立自動增加的主鍵列。

默認建立的主鍵列屬性爲id,可使用pk代替,pk全拼爲primary key。

3) 屬性命名限制
- 不能是python的保留關鍵字。
- 不容許使用連續的下劃線,這是由django的查詢方式決定的。
- 定義屬性時須要指定字段類型,經過字段類型的參數指定選項,語法以下:
  屬性=models.字段類型(選項)
4)字段類型
類型 說明
AutoField 自動增加的IntegerField,一般不用指定,不指定時Django會自動建立屬性名爲id的自動增加屬性
BooleanField 布爾字段,值爲True或False
NullBooleanField 支持Null、True、False三種值
CharField 字符串,參數max_length表示最大字符個數
TextField 大文本字段,通常超過4000個字符時使用
IntegerField 整數
DecimalField 十進制浮點數, 參數max_digits表示總位數, 參數decimal_places表示小數位數
FloatField 浮點數
DateField 日期, 參數auto_now表示每次保存對象時,自動設置該字段爲當前時間,用於"最後一次修改"的時間戳,它老是使用當前日期,默認爲False; 參數auto_now_add表示當對象第一次被建立時自動設置當前時間,用於建立的時間戳,它老是使用當前日期,默認爲False; 參數auto_now_add和auto_now是相互排斥的,組合將會發生錯誤
TimeField 時間,參數同DateField
DateTimeField 日期時間,參數同DateField
FileField 上傳文件字段
ImageField 繼承於FileField,對上傳的內容進行校驗,確保是有效的圖片
5)選項
選項 說明
null 若是爲True,表示容許爲空,默認值是False
blank 若是爲True,則該字段容許爲空白,默認值是False
db_column 字段的名稱,若是未指定,則使用屬性的名稱
db_index 若值爲True, 則在表中會爲此字段建立索引,默認值是False
default 默認
primary_key 若爲True,則該字段會成爲模型的主鍵字段,默認值是False,通常做爲AutoField的選項使用
unique 若是爲True, 這個字段在表中必須有惟一值,默認值是False

            null是數據庫範疇的概念,blank是表單驗證範疇的

6) 外鍵
在設置外鍵時,須要經過**on_delete**選項指明主表刪除數據時,對於外鍵引用表數據如何處理,在django.db.models中包含了可選常量:
- **CASCADE** 級聯,刪除主表數據時連通一塊兒刪除外鍵表中數據
- **PROTECT** 保護,經過拋出**ProtectedError**異常,來阻止刪除主表中被外鍵應用的數據
- **SET_NULL** 設置爲NULL,僅在該字段null=True容許爲null時可用
- **SET_DEFAULT** 設置爲默認值,僅在該字段設置了默認值時可用
- **SET()** 設置爲特定值或者調用特定方法,如
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models

def get_sentinel_user():
    return get_user_model().objects.get_or_create(username='deleted')[0]

class MyModel(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET(get_sentinel_user),
    )
**DO_NOTHING** 不作任何操做,若是數據庫前置指明級聯性,此選項會拋出**IntegrityError**異常

3. 數據遷移(將模型類同步到數據庫中)

1)生成遷移文件
python manage.py makemigrations
2)同步到數據庫中
python manage.py migrate 

4.添加測試數據

insert into tb_books(btitle,bpub_date,bread,bcomment,is_delete) values
('射鵰英雄傳','1980-5-1',12,34,0),
('天龍八部','1986-7-24',36,40,0),
('笑傲江湖','1995-12-24',20,80,0),
('雪山飛狐','1987-11-11',58,24,0);


insert into tb_heros(hname,hgender,hbook_id,hcomment,is_delete) values
('郭靖',1,1,'降龍十八掌',0),
('黃蓉',0,1,'打狗棍法',0),
('黃藥師',1,1,'彈指神通',0),
('歐陽鋒',1,1,'蛤蟆功',0),
('梅超風',0,1,'九陰白骨爪',0),
('喬峯',1,2,'降龍十八掌',0),
('段譽',1,2,'六脈神劍',0),
('虛竹',1,2,'天山六陽掌',0),
('王語嫣',0,2,'神仙姐姐',0),
('令狐沖',1,3,'獨孤九劍',0),
('任盈盈',0,3,'彈琴',0),
('嶽不羣',1,3,'華山劍法',0),
('東方不敗',0,3,'葵花寶典',0),
('胡斐',1,4,'胡家刀法',0),
('苗若蘭',0,4,'黃衣',0),
('程靈素',0,4,'醫術',0),
('袁紫衣',0,4,'六合拳',0);
測試數據

使用pycharm插入數據 方法以下

第一步:

第二部:

第三步

 5. 配置項目路由

1).在全局路由

  

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/',include("booktest.urls"))
]
urls.py

2)在分支路由配置book_test下建立路由文件urls.py

from django.urls import path
from .views import BookAPI
urlpatterns={
    path(r"books/",BookAPI.as_view()),
}

6. 開發圖書相關的數據接口的視圖函數

from django.shortcuts import render

# Create your views here.
# Create your views here.
# 圖書相關的restful api接口
# 獲取全部數據
# 添加一條數據
# 刪除一條數據
# 修改一條數據
from   django.views import View
from  .models import BookInfo
from django.http.response import JsonResponse
class BookAPI(View):
    def get(self,request):
        '''獲取全部圖書數據'''
        #1 操做數據庫
        books=BookInfo.objects.all()
        #2 序列化轉換數據
        data=[]
        for book in books:
            data.append({
                "id":book.id,
                "btitle":book.btitle,
            })
        #3 返回客戶端
        #safe=false 不要對json數據進行安全監測,默認狀況下jsonresponse
        #不能對列表數據進行轉換json
        return JsonResponse(data,safe=False)
views.py

7. 運行項目 

python manage.py migrate

瀏覽器效果:

 七建立rest_framework應用

  1 在窗口執行

python manage.py startapp app

  2.安裝DRF

pip install djangorestframework

  3.全局配置文件seting.py中註冊app

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

- 將請求的數據(如JSON格式)轉換爲模型類對象
- 操做數據庫
- 將模型類對象轉換爲響應的數據(如JSON格式)

  4 在全局路由配置文件中註冊路由  

  drf.urls.py中註冊路由

path('app/', include('app.urls')),

  5  在app應用下建立局部分支路由文件urls.py,代碼以下

from rest_framework.routers import DefaultRouter
from .views import BookInfoAPIView
urlpatterns = [

]
# 建立路由對象
routers = DefaultRouter()
# # 經過路由對象對視圖類進行路由生成
routers.register("books",BookInfoAPIView)
print(">>>>>",routers.urls)
urlpatterns+=routers.urls
urls.py

  6. 建立序列化器

  在app應用中建立序列化器

from rest_framework import serializers
from booktest.models import BookInfo
class BookInfoSerializer(serializers.ModelSerializer):
    """專門用於對圖書進行進行序列化和反序列化的類: 序列化器類"""
    class Meta:
        # 當前序列化器在序列化數據的時候,使用哪一個模型
        model = BookInfo
        # fields = ["id","btitle"] # 多個字段可使用列表聲明,若是是全部字段都要轉換,則使用 '__all__'
        fields = '__all__' # 多個字段可使用列表聲明,若是是全部字段都要轉換,則使用 '__all__'
serialzers.py

  7. 在app應用視圖函數中views.py中序列化數據,代碼以下

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

   8. 重啓應用

訪問DRF應用下的url地址,效果以下:

 八. 序列化器-Serializer

  1. 做用:

1. 序列化,序列化器會把模型對象轉換成字典,通過response之後變成json字符串
2. 完成數據校驗功能
3. 反序列化,把客戶端發送過來的數據,通過request之後變成字典,序列化器能夠把字典轉成模型

  2.定義序列化器  

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

  3 案例

  1)建立序列化器應用 

python manage.py startapp ser

  2)在全局配置文件seting.py中註冊應用  

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'booktest',
    'rest_framework',
    'app',
    'ser',   #序列化器應用
]

  3)路由分發

    1.全局urls.py文件中註冊路由   

path('ser/',include("ser.urls")),

    2.在應用中局部建立urls.py文件並進行分發,代碼以下:

from  django.urls import path,re_path
from  . import views
urlpatterns=[
     path("books/",views.BookInfoView.as_view()),
   path("books2/",views.BookInfo2View.as_view())
   re_path("books2/(?P<pk>\d+)/",views.BookInfo2View.as_view()),
   path("books3/",views.BookInfo3View.as_view()),

]   

  

  4)建立serializers,py文件,並建立序列化器,   代碼及其serializers序列化和反序列化使用方法以下

注意:serializer不是隻能爲數據庫模型類定義,也能夠爲非數據庫模型類的數據定義。serializer是獨立於數據庫以外的存在。使用postman模擬瀏覽器測試

###############################################
###1. 序列化器的序列化階段使用
###############################################
from rest_framework import  serializers
class BookInfo2Serializer(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="邏輯刪除")
#############################################
# 2 序列化器的反序列化階段使用
# 主要用戶驗證數據和字典數據轉換成模型
#############################################
from rest_framework import serializers
from booktest.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])
    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
    # 自定義驗證方法[驗證多個或者全部字段,只能出現一次]
    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
#############################################
# 3 模型序列化器
# 1. 能夠幫咱們自動完成字段的聲明[主要是從模型中的字段聲明裏面提取過來]
# 2. 模型序列化器也能夠幫咱們聲明瞭create和update方法的代碼
#############################################
from rest_framework import serializers
from booktest.models import BookInfo
class BookInfoModelSerializer(serializers.ModelSerializer):
    # 模型序列化器也能夠自定義驗證字段[當某些數據不存在於數據庫時,可是須要前端提交過來的,能夠進行自定義,
    # 例如,驗證碼,確認密碼]

    class Meta:
        model=BookInfo
        fields = "__all__"
        # 能夠給模型序列化器裏面指定的字段設置限制選項
        extra_kwargs = {
            "bread":{"min_value":0,"required":True},
        }

    # 自定義驗證方法[驗證單個字段,能夠有多個方法]
    # def validate_<字段名>(self,data): # data當前字段對應的值
    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("閱讀量小於評論量,數據太假了")
serializers,py

經常使用字段類型

選項參數:

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

通用參數:

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

  5)建立響應視圖圖

#############################################
# 1. 序列化器的序列化階段使用
#############################################
from django.http import JsonResponse
from django.views import View
from booktest.models import BookInfo
# 導入序列化器類
from .serializers import BookInfo2Serializer
class BookInfoView(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)
###############################################################################################################################
# 2 序列化器的反序列化階段使用
# 主要用戶驗證數據和字典數據轉換成模型
# 爲了保證測試順利進行,咱們在settings.py中關閉 csrf的中間件
# 'django.middleware.csrf.CsrfViewMiddleware',
#############################################
from django.views import View
from django.http import JsonResponse
from django.http import QueryDict
from .serializers import BookInfo2Serializer
class BookInfo2View(View):
    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主鍵獲取指定圖書信息
        book = BookInfo.objects.get(pk=pk)
        # 接受到客戶端提交過來的數據
        # data = {
        #     "btitle":"西廂記外傳",
        #     "bpub_date":"1998-10-10",
        #     "bread":"100",
        #     "bcomment":"50"
        # }
        # 獲取put數據
        data = QueryDict(request.body)

        # 使用序列化器完成驗證和反序列化過程
        # partial=True 接下里在反序列化中容許部分數據更新
        serializer = BookInfo2Serializer(instance=book,data=data,partial=True)
        serializer.is_valid(raise_exception=True)
        # save之因此能夠自動識別,何時執行create ,何時執行update
        # 主要是看建立序列化器對象時,是否有傳入instance參數,
        # 有instance參數,則save會調用序列化器內部的update方法
        # 沒有instance參數,則save會調用序列化器內部的create方法
        serializer.save()

        # 響應數據
        return JsonResponse(serializer.data)


#############################################
# 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)

        serializer = BookInfoModelSerializer(instance=book,data=data,partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 響應數據
        return JsonResponse(serializer.data)
Views.py

serializers的總結:

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 序列化器的使用

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

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

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

 

2 序列化

 基本使用

1) 先查詢出一個圖書對象

from booktest.models import BookInfo

book = BookInfo.objects.get(id=2)

2) 構造序列化器對象

from booktest.serializers import BookInfoSerializer

serializer = BookInfoSerializer(book)

3)獲取序列化數據

經過data屬性能夠獲取序列化後的數據

serializer.data
# {'id': 2, 'btitle': '天龍八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40, 'image': None}

 

4)若是要被序列化的是包含多條數據的查詢集QuerySet,能夠經過添加many=True參數補充說明

book_qs = BookInfo.objects.all()
serializer = BookInfoSerializer(book_qs, many=True)
serializer.data
# [OrderedDict([('id', 2), ('btitle', '天龍八部'), ('bpub_date', '1986-07-24'), ('bread', 36), ('bcomment', 40), ('image', N]), OrderedDict([('id', 3), ('btitle', '笑傲江湖'), ('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80), ('image'ne)]), OrderedDict([('id', 4), ('btitle', '雪山飛狐'), ('bpub_date', '1987-11-11'), ('bread', 58), ('bcomment', 24), ('ima None)]), OrderedDict([('id', 5), ('btitle', '西遊記'), ('bpub_date', '1988-01-01'), ('bread', 10), ('bcomment', 10), ('im', 'booktest/xiyouji.png')])]

 

3反序列化

 數據驗證

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

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

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

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

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

如咱們前面定義過的BookInfoSerializer

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)

經過構造序列化器對象,並將要反序列化的數據傳遞給data構造參數,進而進行驗證

from booktest.serializers import BookInfoSerializer
data = {'bpub_date': 123}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # 返回False
serializer.errors
# {'btitle': [ErrorDetail(string='This field is required.', code='required')], 'bpub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]}
serializer.validated_data  # {}

data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # True
serializer.errors  # {}
serializer.validated_data  # OrderedDict([('btitle', 'python')])

is_valid()方法還能夠在驗證失敗時拋出異常serializers.ValidationError,能夠經過傳遞raise_exception=True參數開啓,REST framework接收到此異常,會向前端返回HTTP 400 Bad Request響應。

# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)

若是以爲這些還不夠,須要再補充定義驗證行爲,可使用如下三種方法:

1) validate_字段名

<field_name>字段進行驗證,如

class BookInfoSerializer(serializers.Serializer):
   """圖書數據序列化器"""
  ...

   def validate_btitle(self, value):
       if 'django' not in value.lower():
           raise serializers.ValidationError("圖書不是關於Django的")
       return value

測試

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # False  
serializer.errors
# {'btitle': [ErrorDetail(string='圖書不是關於Django的', code='invalid')]}
2) validate

在序列化器中須要同時對多個字段進行比較驗證時,能夠定義validate方法來驗證,如

class BookInfoSerializer(serializers.Serializer):
   """圖書數據序列化器"""
  ...

   def validate(self, attrs):
       bread = attrs['bread']
       bcomment = attrs['bcomment']
       if bread < bcomment:
           raise serializers.ValidationError('閱讀量小於評論量')
       return attrs

測試

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'about django', 'bread': 10, 'bcomment': 20}
s = BookInfoSerializer(data=data)
s.is_valid()  # False
s.errors
# {'non_field_errors': [ErrorDetail(string='閱讀量小於評論量', code='invalid')]}
3) validators

在字段中添加validators選項參數,也能夠補充驗證行爲,如

def about_django(value):
   if 'django' not in value.lower():
       raise serializers.ValidationError("圖書不是關於Django的")

class BookInfoSerializer(serializers.Serializer):
   """圖書數據序列化器"""
   id = serializers.IntegerField(label='ID', read_only=True)
   btitle = serializers.CharField(label='名稱', max_length=20, validators=[about_django])
   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)

測試:

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # False  
serializer.errors
# {'btitle': [ErrorDetail(string='圖書不是關於Django的', code='invalid')]}

 

4 反序列化-保存數據

前面的驗證數據成功後,咱們可使用序列化器來完成數據反序列化的過程.這個過程能夠把數據轉成模型類對象.

能夠經過實現create()和update()兩個方法來實現。

class BookInfoSerializer(serializers.Serializer):
   """圖書數據序列化器"""
  ...

   def create(self, validated_data):
       """新建"""
       return BookInfo(**validated_data)

   def update(self, instance, validated_data):
       """更新,instance爲要更新的對象實例"""
       instance.btitle = validated_data.get('btitle', instance.btitle)
       instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
       instance.bread = validated_data.get('bread', instance.bread)
       instance.bcomment = validated_data.get('bcomment', instance.bcomment)
       return instance

若是須要在返回數據對象的時候,也將數據保存到數據庫中,則能夠進行以下修改

class BookInfoSerializer(serializers.Serializer):
   """圖書數據序列化器"""
  ...

   def create(self, validated_data):
       """新建"""
       return BookInfo.objects.create(**validated_data)

   def update(self, instance, validated_data):
       """更新,instance爲要更新的對象實例"""
       instance.btitle = validated_data.get('btitle', instance.btitle)
       instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
       instance.bread = validated_data.get('bread', instance.bread)
       instance.bcomment = validated_data.get('bcomment', instance.bcomment)
       instance.save()
       return instance

實現了上述兩個方法後,在反序列化數據的時候,就能夠經過save()方法返回一個數據對象實例了

book = serializer.save()

若是建立序列化器對象的時候,沒有傳遞instance實例,則調用save()方法的時候,create()被調用,相反,若是傳遞了instance實例,則調用save()方法的時候,update()被調用。

from db.serializers import BookInfoSerializer
data = {'btitle': '封神演義'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 封神演義>

from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = {'btitle': '倚天劍'}
serializer = BookInfoSerializer(book, data=data)
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 倚天劍>
book.btitle  # '倚天劍'

 

5 附加說明

1) 在對序列化器進行save()保存時,能夠額外傳遞數據,這些數據能夠在create()和update()中的validated_data參數獲取到

# request.user 是django中記錄當前登陸用戶的模型對象
serializer.save(owner=request.user)

2)默認序列化器必須傳遞全部required的字段,不然會拋出驗證異常。可是咱們可使用partial參數來容許部分字段更新

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

 

 

6 模型類序列化器

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

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

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

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

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

7 定義

好比咱們建立一個BookInfoSerializer

class BookInfoSerializer(serializers.ModelSerializer):
   """圖書數據序列化器"""
   class Meta:
       model = BookInfo
       fields = '__all__'
  • model 指明參照哪一個模型類

  • fields 指明爲模型類的哪些字段生成

咱們能夠在python manage.py shell中查看自動生成的BookInfoSerializer的具體實現

>>> from booktest.serializers import BookInfoSerializer
>>> serializer = BookInfoSerializer()
>>> serializer
BookInfoSerializer():
   id = IntegerField(label='ID', read_only=True)
   btitle = CharField(label='名稱', max_length=20)
   bpub_date = DateField(allow_null=True, label='發佈日期', required=False)
   bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False)
   bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=-2147483648, required=False)
   image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)

8 指定字段

1) 使用fields來明確字段,__all__表名包含全部字段,也能夠寫明具體哪些字段,如

class BookInfoSerializer(serializers.ModelSerializer):
   """圖書數據序列化器"""
   class Meta:
       model = BookInfo
       fields = ('id', 'btitle', 'bpub_date')

2) 使用exclude能夠明確排除掉哪些字段

class BookInfoSerializer(serializers.ModelSerializer):
   """圖書數據序列化器"""
   class Meta:
       model = BookInfo
       exclude = ('image',)

3) 顯示指明字段,如:

class HeroInfoSerializer(serializers.ModelSerializer):
   hbook = BookInfoSerializer()

   class Meta:
       model = HeroInfo
       fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')

4) 指明只讀字段

能夠經過read_only_fields指明只讀字段,即僅用於序列化輸出的字段

class BookInfoSerializer(serializers.ModelSerializer):
   """圖書數據序列化器"""
   class Meta:
       model = BookInfo
       fields = ('id', 'btitle', 'bpub_date''bread', 'bcomment')
       read_only_fields = ('id', 'bread', 'bcomment')

 

9 添加額外參數

咱們可使用extra_kwargs參數爲ModelSerializer添加或修改原有的選項參數

class BookInfoSerializer(serializers.ModelSerializer):
"""圖書數據序列化器"""
class Meta:
  model = BookInfo
  fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
  extra_kwargs = {
  'bread': {'min_value': 0, 'required': True},  
  'bcomment': {'min_value': 0, 'required': True},
}

# BookInfoSerializer():
#    id = IntegerField(label='ID', read_only=True)
#   btitle = CharField(label='名稱', max_length=20)
#    bpub_date = DateField(allow_null=True, label='發佈日期', required=False)
#    bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=0, required=True)
#    bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=0, required=True)

  

  

 

 

 

 

 

 

 

 

 

 

---恢復內容結束---

相關文章
相關標籤/搜索