---恢復內容開始---html
一: web 應用模式(有兩種)前端
1: 先後端不分離(前端從後端直接獲取數據)python
2: 先後端分離mysql
二: api 接口git
緣由一: 爲了在團隊內部造成共識、防止我的習慣差別引發的混亂,咱們須要找到一種你們都以爲很好的接口實現規範,
並且這種規範可以讓後端寫的接口,用途一目瞭然,減小雙方之間的合做成本。 目前市面上大部分公司開發人員使用的接口服務架構主要有:restful、rpc。 1: rpc: 翻譯成中文:遠程過程調用[遠程服務調用]. post請求 action=get_all_student¶ms=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 |
事實上,咱們可使用任何一個框架均可以實現符合restful規範的API接口。web
四: 序列化sql
api接口開發,最核心最多見的一個過程就是序列化,所謂序列化就是把**數據轉換格式**,序列化能夠分兩個階段: 1. 序列化: 把咱們識別的數據轉換成指定的格式提供給別人。 例如:咱們在django中獲取到的數據默認是模型對象,可是模型對象數據沒法直接提供給前端或別的平臺使用,因此咱們須要把數據進行序列化,變成字符串或者json數據,提供給別人。 2.反序列化:把別人提供的數據轉換/還原成咱們須要的格式。 例如:前端js提供過來的json數據,對於python而言就是字符串,咱們須要進行反序列化換成模型類對象,這樣咱們才能把數據保存到數據庫中。
五: 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 |
5)選項
說明 | |
---|---|
null | 若是爲True,表示容許爲空,默認值是False |
blank | 若是爲True,則該字段容許爲空白,默認值是False |
db_column | 字段的名稱,若是未指定,則使用屬性的名稱 |
db_index | 若值爲True, 則在表中會爲此字段建立索引,默認值是False |
default | 默認 |
primary_key | 若爲True,則該字段會成爲模型的主鍵字段,默認值是False,通常做爲AutoField的選項使用 |
unique |
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")) ]
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)
7. 運行項目
python manage.py migrate
瀏覽器效果:
七建立
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
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__'
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
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序列化和反序列化使用方法以下
############################################### ###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("閱讀量小於評論量,數據太假了")
選項參數:
參數名稱 | 做用 |
---|---|
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 |
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)
serializers的總結:
Serializer(instance=None, data=empty, **kwarg)
說明:
1)用於序列化時,將模型類對象傳入instance參數
2)用於反序列化時,將要被反序列化的數據傳入data參數
3)除了instance和data參數外,在構造Serializer對象時,還可經過context參數額外添加數據,如
serializer = AccountSerializer(account, context={'request': request})
經過context參數附加的數據,能夠經過Serializer對象的context屬性獲取。
使用序列化器的時候必定要注意,序列化器聲明瞭之後,不會自動執行,須要咱們在視圖中進行調用才能夠。
序列化器沒法直接接收數據,須要咱們在視圖中建立序列化器對象時把使用的數據傳遞過來。
序列化器的字段聲明相似於咱們前面使用過的表單系統。
開發restful api時,序列化器會幫咱們把模型數據轉換成字典.
drf提供的視圖會幫咱們把字典轉換成json,或者把客戶端發送過來的數據轉換字典.
序列化器的使用分兩個階段:
在客戶端請求時,使用序列化器能夠完成對數據的反序列化。
在服務器響應時,使用序列化器能夠完成對數據的序列化。
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')])]
使用序列化器進行反序列化時,須要對數據進行驗證後,才能獲取驗證成功的數據或保存成模型類對象。
在獲取反序列化的數據前,必須調用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)
若是以爲這些還不夠,須要再補充定義驗證行爲,可使用如下三種方法:
對<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')]}
在序列化器中須要同時對多個字段進行比較驗證時,能夠定義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')]}
在字段中添加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')]}
前面的驗證數據成功後,咱們可使用序列化器來完成數據反序列化的過程.這個過程能夠把數據轉成模型類對象.
能夠經過實現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 # '倚天劍'
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)
若是咱們想要使用序列化器對應的是Django的模型類,DRF爲咱們提供了ModelSerializer模型類序列化器來幫助咱們快速建立一個Serializer類。
ModelSerializer與常規的Serializer相同,但提供了:
基於模型類自動生成一系列字段
基於模型類自動爲Serializer生成validators,好比unique_together
包含默認的create()和update()的實現
好比咱們建立一個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)
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')
咱們可使用extra_kwargs
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)
---恢復內容結束---