在開發Web應用中,有兩種應用模式:html
1. 先後端不分離前端
2. 先後端分離python
爲了在團隊內部造成共識、防止我的習慣差別引發的混亂,咱們須要找到一種你們都以爲很好的接口實現規範,並且這種規範可以讓後端寫的接口,用途一目瞭然,減小雙方之間的合做成本。mysql
目前市面上大部分公司開發人員使用的接口服務架構主要有:restful、rpc。linux
rpc: 翻譯成中文:遠程過程調用[遠程服務調用]. http://www.lufei.com/api post請求 action=get_all_student¶ms=301&sex=1
接口多了,對應函數名和參數就多了,前端在請求api接口時,就會比較難找.容易出現重複的接口git
restful: 翻譯成中文: 資源狀態轉換. 把後端全部的數據/文件都當作資源. 那麼接口請求數據,本質上來講就是對資源的操做了. web項目中操做資源,無非就是增刪查改.因此要求在地址欄中聲明要操做的資源是什麼,而後經過http請求動詞來講明對資源進行哪種操做. POST http://www.lufei.com/api/students/ 添加學生數據 GET http://www.lufei.com/api/students/ 獲取全部學生 DELETE http://www.lufei.com/api/students/<pk> 刪除1個學生 GET http://www.lufei.com/api/students/<pk> 獲取一個學生
REST全稱是Representational State Transfer,中文意思是表述(編者注:一般譯爲表徵)性狀態轉移。 它首次出如今2000年Roy Fielding的博士論文中。github
RESTful是一種定義Web API接口的設計風格,尤爲適用於先後端分離的應用模式中。web
這種風格的理念認爲後端開發任務就是提供數據的,對外提供的是數據資源的訪問接口,因此在定義接口時,客戶端訪問的URL路徑就表示這種要操做的數據資源。sql
而對於數據資源分別使用POST、DELETE、GET、UPDATE等請求動做來表達對數據的增刪查改。shell
請求方法 | 請求地址 | 後端操做 |
---|---|---|
GET | /students | 獲取全部學生 |
POST | /students | 增長學生 |
GET | /students/<pk> | 獲取編號爲pk的學生 |
PUT | /students/<pk> | 修改編號爲pk的學生 |
DELETE | /students/<pk> | 刪除編號爲pk的學生 |
參考文檔:http://www.runoob.com/w3cnote/restful-architecture.html
api接口開發,最核心最多見的一個過程就是序列化,所謂序列化就是把數據轉換格式,序列化能夠分兩個階段:
序列化: 把咱們識別的數據轉換成指定的格式提供給別人。
例如:咱們在django中獲取到的數據默認是模型對象,可是模型對象數據沒法直接提供給前端或別的平臺使用,因此咱們須要把數據進行序列化,變成字符串或者json數據,提供給別人。
反序列化:把別人提供的數據轉換/還原成咱們須要的格式。
例如:前端js提供過來的json數據,對於python而言就是字符串,咱們須要進行反序列化換成模型類對象,這樣咱們才能把數據保存到數據庫中。
接收數據[反序列化]
操做數據
響應數據[序列化]
核心思想: 縮減編寫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 界面; - 可擴展性,插件豐富
前提是已經安裝了django,建議安裝在虛擬環境
# mkvirtualenv drfdemo -p python3 # pip install django pip install djangorestframework pip install pymysql
linux 複製 shift+insert
cd ~/Desktop
django-admin startproject drfdemo
使用pycharm打開項目,設置虛擬環境的解析器,並修改manage.py中的後綴參數。
INSTALLED_APPS = [ ... 'rest_framework', ]
接下來就可使用DRF提供的功能進行api接口開發了。在項目中若是使用rest_framework框架實現API接口,主要有如下三個步驟:
操做數據庫
將模型類對象轉換爲響應的數據(如JSON格式)
接下來,咱們快速體驗下四天後咱們學習完成drf之後的開發代碼。接下來代碼不須要理解,看步驟。
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="個性簽名") class Meta: db_table="tb_student" verbose_name = "學生" verbose_name_plural = verbose_name
爲了方便測試,因此咱們能夠先建立一個數據庫。
create database students charset=utf8;
例如,在django項目中建立學生子應用。
python manage.py startapp students
把students子應用添加到INSTALLED_APPS中
初始化數據庫鏈接
安裝pymysql
pip install pymysql
import pymysql pymysql.install_as_MySQLdb()
settings.py配置文件中設置mysql的帳號密碼
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", } }
終端下,執行數據遷移。
python manage.py makemigrations
python manage.py migrate
執行數據遷移 python manage.py makemigrations 報錯以下:
解決方案:
註釋掉 backends/mysql/base.py中的35和36行代碼。
# 執行數據遷移發生如下錯誤:
解決方法:
backends/mysql/operations.py146行裏面新增一個行代碼:
在students應用目錄中新建serializers.py用於保存該應用的序列化器。
建立一個StudentModelSerializer用於序列化與反序列化。
# 建立序列化器類,回頭會在試圖中被調用 from rest_framework import serializers from .models import Student class StudentModelSerializer(serializers.ModelSerializer): class Meta: model = Student fields = "__all__"
fields 指明該序列化器包含模型類中的哪些字段,'all'指明包含全部字段
from rest_framework.viewsets import ModelViewSet from .models import Student from .serializers import StudentModelSerializer # Create your views here. class StudentViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer
serializer_class 指明該視圖在進行序列化或反序列化時使用的序列化器
from . import views from rest_framework.routers import DefaultRouter # 路由列表 urlpatterns = [] router = DefaultRouter() # 能夠處理視圖的路由器 router.register('students', views.StudentViewSet) # 向路由器中註冊視圖集 urlpatterns += router.urls # 將路由器中的因此路由信息追到到django的路由列表中
from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path("stu/",include("students.urls")), ]
python manage.py runserver
在瀏覽器中輸入網址127.0.0.1:8000,能夠看到DRF提供的API Web瀏覽頁面:
點擊POST後,返回以下頁面信息:
點擊PUT,返回以下頁面信息:
做用:
1. 序列化,序列化器會把模型對象轉換成字典,通過response之後變成json字符串 2. 反序列化,把客戶端發送過來的數據,通過request之後變成字典,序列化器能夠把字典轉成模型 3. 反序列化,完成數據校驗功能
Django REST framework中的Serializer使用類來定義,須繼承自rest_framework.serializers.Serializer。
python manage.py startapp ser
咱們已有了一個數據庫模型類students/Student
from django.db import models # Create your models here. class Student(models.Model): # 模型字段 name = models.CharField(max_length=100,verbose_name="姓名",help_text="提示文本:帳號不能爲空!") sex = models.BooleanField(default=True,verbose_name="性別") age = models.IntegerField(verbose_name="年齡") class_null = models.CharField(max_length=5,verbose_name="班級編號") description = models.TextField(verbose_name="個性簽名") class Meta: db_table="tb_student" verbose_name = "學生" verbose_name_plural = verbose_name
定義以下:
在ser應用下建立一個serializers.py
from rest_framework import serializers # 聲明序列化器,全部的序列化器都要直接或者間接繼承於 Serializer # 其中,ModelSerializer是Serializer的子類,ModelSerializer在Serializer的基礎上進行了代碼簡化 class StudentSerializer(serializers.Serializer): """學生信息序列化器""" # 1. 須要進行數據轉換的字段 id = serializers.IntegerField() name = serializers.CharField() age = serializers.IntegerField() sex = serializers.BooleanField() description = serializers.CharField() # 2. 若是序列化器集成的是ModelSerializer,則須要聲明調用的模型信息 # 3. 驗證代碼 # 4. 編寫添加和更新模型的代碼
字段 | 字段構造方式 serializers.字段構造方式() |
---|---|
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=) |
選項參數:
參數名稱 | 做用 |
---|---|
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頁面時,顯示的字段幫助提示信息 |
from rest_framework import serializers class BookSerializer(serializers.Serializer): #序列化器 Serializer
定義好Serializer類後,就能夠建立Serializer對象了。
Serializer(instance=None, data=empty, **kwarg)
說明:
2)用於反序列化時,將要被反序列化的數據傳入data參數
3)除了instance和data參數外,在構造Serializer對象時,還可經過context參數額外添加數據,如
serializer = StudentSerializer(instance, context={'request': request})
經過context參數附加的數據,能夠經過Serializer對象的context屬性獲取。
序列化器沒法直接接收數據,須要咱們在視圖中建立序列化器對象時把使用的數據傳遞過來。
序列化器的字段聲明相似於咱們前面使用過的表單系統。
開發restful api時,序列化器會幫咱們把模型數據轉換成字典.
drf提供的視圖會幫咱們把字典轉換成json,或者把客戶端發送過來的數據轉換字典.
1) 先查詢出一個學生對象
from students.models import Student student = Student.objects.get(id=3)
2) 構造序列化器對象
from .serializers import StudentSerializer serializer = StudentSerializer(instance=student)
經過data屬性能夠獲取序列化後的數據
serializer.data # {'id': 4, 'name': '小張', 'age': 18, 'sex': True, 'description': '猴賽雷'}
完整視圖代碼:
from django.views import View from students.models import Student from .serializers import StudentSerializer from django.http.response import JsonResponse class StudentRetrieveView(View): """使用序列化器序列化轉換單個模型數據""" def get(self,request,pk): # 獲取數據 student = Student.objects.get(pk=pk) # 數據轉換[序列化過程] serializer = StudentSerializer(instance=student) print(serializer.data) # 響應數據 return JsonResponse(serializer.data)
class StudentView(View): """使用序列化器序列化轉換多個模型數據""" def get(self,request): # 獲取數據 student_list = Student.objects.all() # 轉換數據[序列化過程] # 若是轉換多個模型對象數據,則須要加上many=True serializer = StudentSerializer(instance=student_list,many=True) print( serializer.data ) # 序列化器轉換後的數據 # 響應數據給客戶端 # 返回的json數據,若是是列表,則須要聲明safe=False return JsonResponse(serializer.data,safe=False) # 訪問結果: # [OrderedDict([('id', 1), ('name', 'xiaoming'), ('age', 20), ('sex', True), ('description', '測試')]), OrderedDict([('id', 2), ('name', 'xiaohui'), ('age', 22), ('sex', True), ('description', '後面來的測試')]), OrderedDict([('id', 4), ('name', '小張'), ('age', 18), ('sex', True), ('description', '猴賽雷')])]
models
from django.db import models # Create your models here. 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="個性簽名") class Meta: db_table="tb_student" verbose_name = "學生" verbose_name_plural = verbose_name
項目下的url
from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('ser/', include('ser.urls')), ]
項目下settings的
INSTALLED_APPS = [ 'rest_framework', 'ser', ]
ser下url
from django.urls import re_path,path # re_path正則 from . import views urlpatterns = [ path("students/", views.StudentView.as_view() ), re_path("students/(?P<pk>\d+)/", views.StudentRetrieveView.as_view() ), ]
ser下serializers.py,手動建立
from rest_framework import serializers # 聲明序列化器,全部的序列化器都要直接或者間接繼承於 Serializer # 其中,ModelSerializer是Serializer的子類,ModelSerializer在Serializer的基礎上進行了代碼簡化 class StudentSerializer(serializers.Serializer): """學生信息序列化器""" # 1. 須要進行數據轉換的字段 id = serializers.IntegerField() name = serializers.CharField() age = serializers.IntegerField() sex = serializers.BooleanField() description = serializers.CharField() # 2. 若是序列化器集成的是ModelSerializer,則須要聲明調用的模型信息 # 3. 驗證代碼 # 4. 編寫添加和更新模型的代碼
ser下views
from django.shortcuts import render # Create your views here. from django.views import View from students.models import Student from .serializers import StudentSerializer from django.http import JsonResponse class StudentView(View): """調用序列化器進行序列化操做""" def get(self,request): """提供全部學生信息""" student_list = Student.objects.all() print(student_list) # 列表,列表裏面的每個成員都是一個模型對象 # 使用序列化器進行數據轉換列表的每個成員爲字典 # 1. 實例化序列化器類 # StudentSerializer(instance, data, context={視圖中要發送給序列化器中使用的字典數據}) # 參數instance ,模型對象,這個參數通常用於把模型轉成字典,進行序列化 # 參數data,客戶端提交的字典數據,這個參數通常用於把字典轉成模型對象,進行校驗數據和反序列化 # 參數context,有時候,路由或者視圖中有些數據須要傳遞序列化器內部的方法中調用,則能夠context以字典的格式傳遞進行 # 額外參數: many=True, 表示instance是一個模型列表,此時序列化器在轉換數據的時候能夠進行循環 serializer = StudentSerializer(student_list, many=True) print(111,serializer.data ) # 獲取轉換後的數據 # 關閉json數據的安全檢測, safe=False return JsonResponse(serializer.data,safe=False) class StudentRetrieveView(View): def get(self,request,pk): """獲取一個學生信息""" student = Student.objects.get(pk=pk) print(student) serializer = StudentSerializer(student) print(serializer.data) return JsonResponse(serializer.data)
在獲取反序列化的數據前,必須調用is_valid()方法進行驗證,驗證成功返回True,不然返回False。
驗證失敗,能夠經過序列化器對象的errors屬性獲取錯誤信息,返回字典,包含了字段和字段的錯誤。若是是非字段錯誤,能夠經過修改REST framework配置中的NON_FIELD_ERRORS_KEY來控制錯誤字典中的鍵名。
驗證成功,能夠經過序列化器對象的validated_data屬性獲取數據。
在定義序列化器時,指明每一個字段的序列化類型和選項參數,自己就是一種驗證行爲。
爲了方便學習,咱們新建一個子應用books。
python manage.py startapp books
在settings.py中的INSTALLED_APPS中新增books子應用
INSTALLED_APPS = [ # ... 'ser', 'unser', ]
Book模型,代碼:
models
from django.db import models class Book(models.Model): """圖書模型""" title = models.CharField(verbose_name='名稱', max_length=20) pub_date = models.DateField(verbose_name='發佈日期') read = models.IntegerField(verbose_name='閱讀量',default=0) comment = models.IntegerField(verbose_name='評論量', null=True, blank=True) class Meta: db_table = "tb_book" verbose_name="圖書" verbose_name_plural=verbose_name def __str__(self): return self.title
執行數據遷移,代碼:
python manage.py makemigrations
python manage.py migrate
BookSerializer序列化器,代碼:
三種驗證方式
1. 外部函數設置爲驗證函數
函數
字段內加 validators=[check_title]
2. 字段 = serializers.字段類型(驗證選項)
error_messages={"min_value":"xxxx"}
3. 自定義方法設置校驗方法
單字段
def validate_字段(self, data)
raise serializers.ValidationError()
多字段
· def validate(self, data):
字段 = data.get('字段')
字段 = data.get('字段')
raise serializers.ValidationError()
from rest_framework import serializers # 外部函數設置爲驗證函數 def check_title(data): if data == "django入門": raise serializers.ValidationError("這本書,我定了,你不能叫") class BookSerializer(serializers.Serializer): # 字段聲明 # 字段 = serializers.字段類型(驗證選項) title = serializers.CharField(required=True, max_length=20,validators=[check_title]) pub_date = serializers.DateField(required=True) read = serializers.IntegerField(default=0,min_value=0, error_messages={"min_value":"對不起,當前字段必須大於或等於0"}) comment = serializers.IntegerField(allow_null=True) # 自定義方法設置校驗方法 # validate_字段(字段值) 用於驗證指定字段 # validate(客戶端提交的全部數據) 用於驗證多個字段[聯合驗證] def validate_title(self, data): if("oldboy" in data): # 跑出錯誤 raise serializers.ValidationError("對不起,圖書名不能包含oldboy!") # 必須在校驗完成之後,返回結果 return data def validate(self, data): read = data.get("read") comment = data.get("comment") if(comment>read): raise serializers.ValidationError("對不起,閱讀量不能小於評論量,噴子!") return data
經過構造序列化器對象,並將要反序列化的數據傳遞給data構造參數,進而進行驗證
from book.serializers import BookSerializer data = {'pub_date': 123} serializer = BookSerializer(data=data) serializer.is_valid() # 返回False serializer.errors # {'title': [ErrorDetail(string='This field is required.', code='required')], 'pub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]} serializer.validated_data # {} data = {'title': 'python'} serializer = BookSerializer(data=data) serializer.is_valid() # True 驗證結果返回值 serializer.errors # {} 錯誤信息 serializer.validated_data # OrderedDict([('btitle', 'python')])
# Return a 400 response if the data was invalid. serializer.is_valid(raise_exception=True)
若是以爲這些還不夠,須要再補充定義驗證行爲,可使用如下三種方法:
對<field_name>
class BookSerializer(serializers.Serializer): """圖書數據序列化器""" ... def validate_title(self, value): if 'django' not in value.lower(): raise serializers.ValidationError("圖書不是關於Django的") return value
測試
from book.serializers import BookSerializer data = {'title': 'python'} serializer = BookSerializer(data=data) serializer.is_valid() # False serializer.errors # {'title': [ErrorDetail(string='圖書不是關於Django的', code='invalid')]}
在序列化器中須要同時對多個字段進行比較驗證時,能夠定義validate方法來驗證,如
class BookSerializer(serializers.Serializer): """圖書序列化器""" ... def validate(self, attrs): read = attrs['read'] comment = attrs['comment'] if read < comment: raise serializers.ValidationError('閱讀量小於評論量,不能夠經過') return attrs
測試
from book.serializers import BookSerializer data = {'title': 'about django', 'read': 10, 'comment': 20} s = BookSerializer(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 BookSerializer(serializers.Serializer): """圖書序列化器""" id = serializers.IntegerField(label='ID', read_only=True) title = serializers.CharField(label='名稱', max_length=20, validators=[about_django]) pub_date = serializers.DateField(label='發佈日期', required=False) read = serializers.IntegerField(label='閱讀量', required=False) comment = serializers.IntegerField(label='評論量', required=False)
測試:
from book.serializers import BookSerializer data = {'title': 'python'} serializer = BookSerializer(data=data) serializer.is_valid() # False serializer.errors # {'title': [ErrorDetail(string='圖書不是關於Django的', code='invalid')]}
setting下的url
from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('unser/', include('unser.urls')), ]
unser下url
from django.urls import re_path,path from . import views urlpatterns = [ path("books/", views.BookView.as_view()), ]
models
from django.db import models class Book(models.Model): """圖書模型""" title = models.CharField(verbose_name='名稱', max_length=20) pub_date = models.DateField(verbose_name='發佈日期') read = models.IntegerField(verbose_name='閱讀量',default=0) comment = models.IntegerField(verbose_name='評論量', null=True, blank=True) class Meta: db_table = "tb_book" verbose_name="圖書" verbose_name_plural=verbose_name def __str__(self): return self.title
serializers
from rest_framework import serializers # 外部函數設置爲驗證函數 def check_title(data): if data == "django入門": raise serializers.ValidationError("這本書,我定了,你不能叫") class BookSerializer(serializers.Serializer): # 字段聲明 # 字段 = serializers.字段類型(驗證選項) title = serializers.CharField(required=True, max_length=20,validators=[check_title]) pub_date = serializers.DateField(required=True) read = serializers.IntegerField(default=0,min_value=0, error_messages={"min_value":"對不起,當前字段必須大於或等於0"}) comment = serializers.IntegerField(allow_null=True) # 自定義方法設置校驗方法 # validate_字段(字段值) 用於驗證指定字段 # validate(客戶端提交的全部數據) 用於驗證多個字段[聯合驗證] def validate_title(self, data): if("oldboy" in data): # 跑出錯誤 raise serializers.ValidationError("對不起,圖書名不能包含oldboy!") # 必須在校驗完成之後,返回結果 return data def validate(self, data): read = data.get("read") comment = data.get("comment") if(comment>read): raise serializers.ValidationError("對不起,閱讀量不能小於評論量,噴子!") return data
views
from django.views import View from django.http import JsonResponse from .serializers import BookSerializer class BookView(View): """使用序列化器完成反序列化和驗證數據功能""" def get(self, request): """添加一個圖書信息""" # data_bytes = request.body # import json # data_dict = json.loads(data_bytes) # print(data_dict) # {'title': 'python入門'} data_dict = { "title": "django入門", "pub_date": "2009-10-10", # "read": -10000, # 模擬失敗的狀況 "read": 10000, "comment": 300 } # 使用序列化器進行反序列化校驗 serializer = BookSerializer(data=data_dict) ret = serializer.is_valid(raise_exception=True) # raise_exception=True 主動中止程序執行,並拋出錯誤 print(ret) # 獲取校驗後的錯誤信息 print(serializer.errors) """打印效果: {'read': [ErrorDetail(string='對不起,當前字段必須大於或等於0', code='min_value')]} """ # 獲取校驗後的數據 print(serializer.validated_data) """打印效果: from collections import OrderedDict OrderedDict([ ('title', 'python入門'), ('pub_date', datetime.date(2009, 10, 10)), ('read', 10000), ('comment', 300) ]) """ return JsonResponse({"message": "ok"})
前面的驗證數據成功後,咱們可使用序列化器來完成數據反序列化的過程.這個過程能夠把數據轉成模型類對象.
class BookSerializer(serializers.Serializer):
"""圖書數據序列化器""" ...
def create(self, validated_data): """添加數據""" instance = Book.objects.create(**validated_data) return instance def update(self, instance, validated_data): """修改數據""" instance.title = validated_data.get("title") instance.pub_date = validated_data.get("pub_date") instance.read = validated_data.get("read") instance.comment = validated_data.get("comment") # 下面的save是調用了ORM中提供給模型保存數據的save,不是序列化器中的save instance.save() return instance
views
from django.views import View from django.http import JsonResponse from .serializers import BookSerializer class BookView(View): """使用序列化器完成反序列化和驗證數據功能""" # 新增 def get2(self,request): """使用序列化器在反序列化時添加數據""" data_dict = { "title":"路飛項目實戰1990", "pub_date":"2009-10-10", "read": 10000, "comment": 300 } serializer = BookSerializer(data=data_dict) serializer.is_valid(raise_exception=True) # 調用序列化器內部保存數據的方法[自動調用create或者update] # 在源碼save方法207行中,系統經過判斷初始化序列化器時是否傳遞了instance參數做爲判斷依據, # 傳遞了instance,則save方法中調用update # 沒有傳遞instance,則save方法中調用create serializer.save() return JsonResponse({"message":"ok"}) # 編輯 def get(self,request): """使用圖序列化器在反序列化時修改數據""" data_dict = { "title":"路飛項目實戰2019", "pub_date":"2019-10-10", "read": 10000, "comment": 300 } pk = 2 # 編輯 book = Book.objects.get(pk=pk) serializer = BookSerializer(instance=book, data=data_dict) serializer.is_valid(raise_exception=True) serializer.save() return JsonResponse(serializer.data)
方法返回一個數據對象實例了
book = serializer.save()
若是建立序列化器對象的時候,沒有傳遞instance實例,則調用save()方法的時候,create()被調用,相反,若是傳遞了instance實例,則調用save()方法的時候,update()被調用。
from .serializers import BookSerializer data = {'title': 'python入門指南'} serializer = BookSerializer(data=data) serializer.is_valid() # True serializer.save() # <BookInfo: python入門指南> from .models import Book book = Book.objects.get(id=2) data = {'title': 'django入門指南'} serializer = BookSerializer(book, data=data) serializer.is_valid() # True serializer.save() # <BookInfo: django入門指南> book.title # 'django入門指南'
1) 在對序列化器進行save()保存時,能夠額外傳遞數據,這些數據能夠在create()和update()中的validated_data參數獲取到
# request.user 是django中記錄當前登陸用戶的模型對象 serializer.save(自定義字段名=request.user,自定義字段名2=xxx)
2)默認序列化器必須傳遞全部required的字段,不然會拋出驗證異常。可是咱們可使用partial參數來容許部分字段更新
# Update `comment` with partial data serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
若是咱們想要使用序列化器對應的是Django的模型類,DRF爲咱們提供了ModelSerializer模型類序列化器來幫助咱們快速建立一個Serializer類。
基於模型類自動生成一系列字段聲明
基於模型類自動爲Serializer生成validators,好比unique_together
包含默認的create()和update()的實現
from rest_framework import serializers class BookModelSerializer(serializers.ModelSerializer): # ModelSerializer 模型序列化器
class BookModelSerializer(serializers.ModelSerializer): """圖書數據序列化器""" # 元類 class Meta: model = Book # 生命當前使用的模型類 fields = '__all__' # 複製全部的字段聲明 fields = ['id','title']# 選擇字段 exclude = ['read'] # 排除字段
fields 指明爲模型類的哪些字段生成
>>> from booktest.serializers import BookSerializer >>> serializer = BookSerializer() >>> serializer BookSerializer(): id = IntegerField(label='ID', read_only=True) title = CharField(label='名稱', max_length=20) pub_date = DateField(allow_null=True, label='發佈日期', required=False) read = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False) comment = IntegerField(label='評論量', max_value=2147483647, min_value=-2147483648, required=False)
class BookSerializer(serializers.ModelSerializer): """圖書數據序列化器""" class Meta: model = Book fields = "__all__"
class BookSerializer(serializers.ModelSerializer): """圖書數據序列化器""" class Meta: model = Book exclude = ('pub_date',)
3) 顯示指明字段,如:
class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ('id', 'title', 'comment', 'read')
4) 指明只讀字段
class BookSerializer(serializers.ModelSerializer): """圖書序列化器""" class Meta: model = Book fields = ('id', 'title', 'pub_date', 'read', 'comment') read_only_fields = ('id', 'read', 'comment')
class BookSerializer(serializers.ModelSerializer): """圖書序列化器""" class Meta: model = Book fields = ('id', 'title', 'pub_date', 'read', 'comment') extra_kwargs = { 'read': {'min_value': 0, 'required': True}, 'comment': {'min_value': 0, 'required': True}, } # BookSerializer(): # id = IntegerField(label='ID', read_only=True) # title = CharField(label='名稱', max_length=20) # pub_date = DateField(allow_null=True, label='發佈日期', required=False) # read = IntegerField(label='閱讀量', max_value=2147483647, min_value=0, required=True) # comment = IntegerField(label='評論量', max_value=2147483647, min_value=0, required=True)
serializers
"""使用模型類序列化器""" from rest_framework import serializers from .models import Book class BookModelSerializer(serializers.ModelSerializer): """字段聲明""" """元類""" class Meta: model = Book # 聲明當前使用的模型類 fields = "__all__" # 複製全部的字段聲明過來
view
"""使用模型類序列化器""" from .serializers import BookModelSerializer from .models import Book class BookView2(View): def get1(self,request): """使用模型類序列化器進行序列化""" """提供全部的圖書信息""" book_list = Book.objects.all() serializer = BookModelSerializer(instance=book_list, many=True) return JsonResponse(serializer.data,safe=False)
serializers
"""使用模型類序列化器""" from rest_framework import serializers from .models import Book class BookModelSerializer(serializers.ModelSerializer): """字段聲明""" """元類""" class Meta: model = Book # 聲明當前使用的模型類 fields = "__all__" # 複製全部的字段聲明過來 # fields = ["id","title","read","pub_date"] # 額外的字段聲明 extra_kwargs = { "title":{ "error_messages":{"max_length":"對不起,當前字段不能超過20個字符"} } } # 自定義方法設置校驗方法 def validate_title(self, data): if("oldboy" in data): # 跑出錯誤 raise serializers.ValidationError("對不起,圖書名不能包含oldboy!") # 必須在校驗完成之後,返回結果 return data def validate(self, data): read = data.get("read") comment = data.get("comment") if(comment>read): raise serializers.ValidationError("對不起,閱讀量不能小於評論量,噴子!") return data
views
"""使用模型類序列化器""" from .serializers import BookModelSerializer from .models import Book class BookView2(View): def get(self,request): data_dict = { "title":"django入門3333", "pub_date":"2009-10-10", # "read": -10000, # 模擬失敗的狀況 "read": 100, "comment": 30 } serializer = BookModelSerializer(data=data_dict) serializer.is_valid(raise_exception=True) print(serializer.errors) serializer.save() return JsonResponse(serializer.validated_data, safe=False)