作用:
1.序列化,序列化器會把模型對象轉(zhuǎn)換成字典,經(jīng)過response以后變成Json字符串
反序列化,序列化器會把客戶端發(fā)送過來的數(shù)據(jù)两入,經(jīng)過request以后變成字典,把字典轉(zhuǎn)化成模型
完成數(shù)據(jù)校驗(yàn)功能敲才。
一裹纳、定義序列化器
Django REST Framework中的Serializer使用類來定義择葡,繼承自rest_framework.serializers.Serializer
舉個(gè)例子:
1.創(chuàng)建一個(gè)新的子應(yīng)用sers
$ python manage.py startapp sers
2.建一個(gè)模型類,這里我們沿用上一篇中的模型類students/Student 參考上一篇的鏈接:http://www.reibang.com/p/d082f7e5b5cb
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="個(gè)性簽名")
class Meta:
db_table="tb_student"
verbose_name = "學(xué)生"
verbose_name_plural = verbose_name
3.為上面這個(gè)模型類提供一個(gè)序列化器敏储,可以定義如下:
from rest_framework import serializers
# 聲明序列化器,所有的序列化器都要直接或者間接繼承于 Serializer
# 其中朋鞍,ModelSerializer是Serializer的子類已添,ModelSerializer在Serializer的基礎(chǔ)上進(jìn)行了代碼簡化
class StudentSerializer(serializers.Serializer):
"""學(xué)生信息序列化器"""
# 1. 需要進(jìn)行數(shù)據(jù)轉(zhuǎn)換的字段
id = serializers.IntegerField()
name = serializers.CharField()
age = serializers.IntegerField()
sex = serializers.BooleanField()
description = serializers.CharField()
# 2. 如果序列化器集成的是ModelSerializer,則需要聲明調(diào)用的模型信息
# 3. 驗(yàn)證代碼
# 4. 編寫添加和更新模型的代碼
注意:serializer不僅僅只能夠?yàn)閿?shù)據(jù)庫模型類定義滥酥,也可以為非數(shù)據(jù)庫模型類的數(shù)據(jù)定義更舞。serializer是獨(dú)立于數(shù)據(jù)庫之外的存在。
常用字段類型:
字段 | 字段構(gòu)造方式 |
---|---|
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) 正則字段坎吻,驗(yàn)證正則模式 [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: 最多位數(shù) decimal_palces: 小數(shù)點(diǎn)位置 |
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=) |
選項(xiàng)參數(shù):
參數(shù)名稱 | 作用 |
---|---|
max_length | 最大長度 |
min_lenght | 最小長度 |
allow_blank | 是否允許為空 |
trim_whitespace | 是否截?cái)嗫瞻鬃址?/td> |
max_value | 最小值 |
min_value | 最大值 |
通用參數(shù):
參數(shù)名稱 | 說明 |
---|---|
read_only | 表明該字段僅用于序列化輸出缆蝉,默認(rèn)False |
write_only | 表明該字段僅用于反序列化輸入,默認(rèn)False |
required | 表明該字段在反序列化時(shí)必須輸入瘦真,默認(rèn)True |
default | 反序列化時(shí)使用的默認(rèn)值 |
allow_null | 表明該字段是否允許傳入None刊头,默認(rèn)False |
validators | 該字段使用的驗(yàn)證器 |
error_messages | 包含錯(cuò)誤編號與錯(cuò)誤信息的字典 |
label | 用于HTML展示API頁面時(shí),顯示的字段名稱 |
help_text | 用于HTML展示API頁面時(shí)吗氏,顯示的字段幫助提示信息 |
4.創(chuàng)建Serializer對象
定義好Serializer類之后芽偏,就可以創(chuàng)建Serializer對象了雷逆。
Serializer的構(gòu)造方法:
Serializer(instance=None, data=empty, **kwarg)
說明:
1. 用于序列化時(shí)弦讽,將模型類對象傳入instance參數(shù)
2. 用于反序列化時(shí),將要被反序列化的數(shù)據(jù)傳入data參數(shù)
3. 除了instance和data參數(shù)外膀哲,在構(gòu)造Serializer對象時(shí)往产,還可以通過context參數(shù)額外添加數(shù)據(jù),如:
serializer = AccountSerializer(account, context= {'request': request})
通過context參數(shù)附加的數(shù)據(jù)某宪,可以通過Serializer對象的context屬性獲取仿村。
使用序列化器時(shí)要注意的幾個(gè)關(guān)鍵點(diǎn):
1. 序列化器聲明以后,不會自動執(zhí)行兴喂,需要我們在視圖中進(jìn)行調(diào)用蔼囊。
2. 序列化器無法直接接收數(shù)據(jù),需要我們在視圖中創(chuàng)建序列化器對象時(shí)把使用的數(shù)據(jù)傳遞過來衣迷。
3. 序列化器的字段聲明類似于我們前面使用過的表單系統(tǒng)畏鼓。
4. 開發(fā)restful api時(shí),序列化器會幫我們把模型數(shù)據(jù)轉(zhuǎn)換成字典壶谒。
5. DRF提供的視圖會幫助我們把字典轉(zhuǎn)換成json云矫,或者把客戶端發(fā)送過來的數(shù)據(jù)轉(zhuǎn)成字典。
5.使用序列化器
序列化器的使用分為兩個(gè)階段:
1. 在客戶端請求時(shí)汗菜,使用序列化器可以完成對數(shù)據(jù)的反序列化让禀。
2. 在服務(wù)器響應(yīng)時(shí)挑社,使用序列化器可以萬彩城對數(shù)據(jù)的序列化。
5.1序列化的基本使用(仍然以Student模型類為例)
第一步:"找對象"
查詢出一個(gè)學(xué)生對象(需要序列化的任意對象)
from students.models import Student
student = Studnent.objects.get(id=3)
第二步:"搞對象"
把學(xué)生對象傳到序列化器類里面巡揍,構(gòu)造出序列化器對象
from .serializers import StudentSerializer
serializer = StudentSerializer(instance=student)
第三步:"開花結(jié)果"
通過序列化器對象的data屬性可以獲取序列化后的數(shù)據(jù)
serializer.data
# {'id': 4, 'name': 'Gavin', 'age': 18, 'sex': True, 'description': '享受知識(姿勢)帶來的樂趣'}
完整的視圖代碼(單個(gè)模型數(shù)據(jù))
from django.views import View
from students.models import Student
from .serializers import StudentSerializer
from django.http.response import JsonResponse
class StudentView(View):
"""使用序列化器序列化轉(zhuǎn)換單個(gè)模型數(shù)據(jù)"""
def get(self,request,pk):
# 獲取模型類對象
student = Student.objects.get(pk=pk)
#構(gòu)造序列化器對象痛阻,所有的結(jié)果都在data里面了[序列化過程]
serializer = StudentSerializer(instance=student)
print(serializer.data)
# 響應(yīng)數(shù)據(jù)
return JsonResponse(serializer.data)
完整的視圖代碼(多個(gè)模型數(shù)據(jù))
from django.views import View
from students.models import Student
from .serializers import StudentSerializer
from django.http.response import JsonResponse
class StudentView(View):
"""使用序列化器序列化轉(zhuǎn)換多個(gè)模型數(shù)據(jù)"""
def get(self,request):
# 獲取模型類對象
student_list = Student.objects.all()
# 構(gòu)造序列化器對象,所有的結(jié)果都在data里面了[序列化過程]
# 如果轉(zhuǎn)換多個(gè)模型對象數(shù)據(jù)腮敌,則需要加上many=True
serializer = StudentSerializer(instance=student_list,many=True)
print( serializer.data ) # 序列化器轉(zhuǎn)換后的數(shù)據(jù)
# 響應(yīng)數(shù)據(jù)給客戶端
# 返回的json數(shù)據(jù)录平,如果是列表,則需要聲明safe=False
return JsonResponse(serializer.data,safe=False)
# 訪問結(jié)果:
# [OrderedDict([('id', 1), ('name', 'Gaivin'), ('age', 18), ('sex', True), ('description', '測試')]), OrderedDict([('id', 2), ('name', 'Carrie'), ('age', 16), ('sex', False), ('description', '后面來的測試')]), OrderedDict([('id', 4), ('name', '小張'), ('age', 18), ('sex', True), ('description', '猴賽雷')])]
5.2數(shù)據(jù)驗(yàn)證
使用序列化器進(jìn)行反序列化時(shí)缀皱,需要對數(shù)據(jù)進(jìn)行驗(yàn)證后斗这,才能獲取驗(yàn)證成功的數(shù)據(jù)或保存成模型類對象。
在獲取反序列化數(shù)據(jù)前啤斗,必須調(diào)用is_valid()方法進(jìn)行驗(yàn)證表箭,驗(yàn)證成功返回Ture,否則返回False钮莲。
驗(yàn)證失敗免钻,可以通過序列化器對象的errors屬性獲取錯(cuò)誤信息,返回字典崔拥,包含了字段和字段的錯(cuò)誤极舔。如果是非字段錯(cuò)誤,可以通過修改REST framework配置中的NON_FILED_ERRORS_KEY來控制錯(cuò)誤自電腦中的鍵名链瓦。
驗(yàn)證成功拆魏,可以通過序列化器對象的validated_data**屬性獲取數(shù)據(jù)。
在定義序列化器時(shí)慈俯,指明每個(gè)字段的序列化類型和選項(xiàng)參數(shù)渤刃,這本身就是一種驗(yàn)證行為。
舉個(gè)例子:我們定義一個(gè)BookInfoSerializer
from rest_framework import serializers
from .serializers import StudentSerializer
class BookInfoSerializer(serializers.Serializer):
"""圖書數(shù)據(jù)序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20)
bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
通過構(gòu)造序列化器對象贴膘,并將要反序列化的數(shù)據(jù)傳遞給data構(gòu)造參數(shù)卖子,進(jìn)而進(jìn)行驗(yàn)證
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()方法還可以在驗(yàn)證失敗時(shí)拋出異常serializers.ValidationError,可以通過傳遞raise_exception=True參數(shù)開啟刑峡,REST framework接收此異常洋闽,會向前端返回HTTP 400 Bad Request響應(yīng)。
# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)
如果覺得這些還不夠突梦,需要在補(bǔ)充驗(yàn)證行為诫舅,可以使用以下三種方法:
1. validate_<field_name>
對<field_name>字段進(jìn)行驗(yàn)證:
from rest_framework import serializers
class BookInfoSerializer(serializers.Serializer):
"""圖書數(shù)據(jù)序列化器"""
...
def validate_btitle(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError("圖書不是關(guān)于Django的")
return value
運(yùn)行,看一下結(jié)果
from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # False
serializer.errors
# {'btitle': [ErrorDetail(string='圖書不是關(guān)于Django的', code='invalid')]}
2.validate方法
在序列化器中需要同時(shí)對多個(gè)字段進(jìn)行比較驗(yàn)證時(shí)阳似,可以定義validate方法來驗(yàn)證骚勘,例如:
class BookInfoSerializer(serializers.Serializer):
"""圖書數(shù)據(jù)序列化器"""
...
def validate(self, attrs):
bread = attrs['bread']
bcomment = attrs['bcomment']
if bread < bcomment:
raise serializers.ValidationError('閱讀量小于評論量')
return attrs
運(yùn)行,看一下結(jié)果
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選項(xiàng)參數(shù),衣蛾可以補(bǔ)充驗(yàn)證行為俏讹,例如:
def about_django(value):
if 'django' not in value.lower():
raise serializers.ValidationError("圖書不是關(guān)于Django的")
class BookInfoSerializer(serializers.Serializer):
"""圖書數(shù)據(jù)序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20, validators=[about_django])
bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
運(yùn)行当宴,看一下結(jié)果
from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # False
serializer.errors
# {'btitle': [ErrorDetail(string='圖書不是關(guān)于Django的', code='invalid')]}
5.3反序列化的使用
前面的驗(yàn)證數(shù)據(jù)成功后,我們可以使用序列化器來完成數(shù)據(jù)反序列化的過程泽疆。這個(gè)過程可以把數(shù)據(jù)轉(zhuǎn)換成模型類對象户矢。
可以通過實(shí)現(xiàn)create()和update()兩個(gè)方法來實(shí)現(xiàn)。
class BookInfoSerializer(serializers.Serializer):
"""圖書數(shù)據(jù)序列化器"""
...
def create(self, validated_data):
"""新建"""
return BookInfo(**validated_data)
def update(self, instance, validated_data):
"""更新殉疼,instance為要更新的對象實(shí)例"""
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
如果需要在返回?cái)?shù)據(jù)對象的時(shí)候梯浪,也將數(shù)據(jù)保存到數(shù)據(jù)庫中,則可以進(jìn)行如下修改:
class BookInfoSerializer(serializers.Serializer):
"""圖書數(shù)據(jù)序列化器"""
...
def create(self, validated_data):
"""新建"""
return BookInfo.objects.create(**validated_data)
def update(self, instance, validated_data):
"""更新瓢娜,instance為要更新的對象實(shí)例"""
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
實(shí)現(xiàn)了上述兩個(gè)方法后挂洛,在反序列化的時(shí)候,就可以通過save()方法返回一個(gè)數(shù)據(jù)對象實(shí)例了
book = serializer.save()
如果創(chuàng)建序列化器對象的時(shí)候眠砾,沒有傳遞instance實(shí)例虏劲,則調(diào)用save()方法的時(shí)候,create()被調(diào)用褒颈,相反柒巫,如果傳遞了instance實(shí)例,則調(diào)用save()方法的時(shí)候谷丸,update()被調(diào)用堡掏。
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 # '倚天劍'
知識點(diǎn)補(bǔ)充:
1. 在對序列化器進(jìn)行save()保存時(shí),可以額外傳遞數(shù)據(jù)刨疼,這些數(shù)據(jù)可以再create()和update()中的validated_data參數(shù)獲取到
# request.user 是django中記錄當(dāng)前登錄用戶的模型對象
serializer.save(owner=request.user)
- 默認(rèn)序列化器必須傳遞所有的required字段泉唁,否則會拋出驗(yàn)證異常。但是我們可以使用partial參數(shù)來允許部分字段更新
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)