寫在前面:
'''
序列化器:
實(shí)質(zhì): 定義了一個(gè)叫做 xx序列化器 的 <類>嗓违,
作用:
1. 實(shí)現(xiàn) <json> 和 <對(duì)象> 的相互轉(zhuǎn)化
2. 實(shí)現(xiàn)對(duì) 前端數(shù)據(jù) 的校驗(yàn)功能
序列化 讀妊鏊啊(read_only) 數(shù)據(jù)庫(kù) obj(數(shù)據(jù)庫(kù)) -> json
反序列化 寫入 (write_only) 數(shù)據(jù)庫(kù) json -> obj(數(shù)據(jù)庫(kù))
'''
1. 定義創(chuàng)建序列化類( 子應(yīng)用中缺虐,新建 serializers.py)
from rest_framework import serializers
# 新建 BookInfoSerializer 序列化器
class BookInfoSerializer(serializers.Serializer): # 記得 Serializer 的 "S" 大寫
id = serializers.IntegerField(read_only=True)
# validators 定義 name 采用 自定義的 custom_validate 驗(yàn)證方式
name = serializers.CharField(max_length=20, label='名字', validators=[custom_validate])
pub_date = serializers.DateField(required=False)
readcount = serializers.IntegerField(required=False)
commentcount = serializers.IntegerField(required=False)
# 設(shè)置標(biāo)記刪除狀態(tài)為 write_only=True, 因?yàn)?我不需要返回給前端 是否刪除標(biāo)記
is_delete = serializers.BooleanField(write_only=True, required=False)
image = serializers.ImageField(write_only=True, required=False)
# 設(shè)置 隱藏字段 | 獲取書籍包含的 所有 英雄 有 多個(gè), 所以添加 many=True
peopleinfo_set = serializers.StringRelatedField(many=True, required=False)
# 新建 PeopleInfoSerializer 序列化器
class PeopleInfoSerializer(serializers.Serializer):
"""人物數(shù)據(jù) 序列化器"""
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
id = serializers.IntegerField(label='ID', read_only=True)
name = serializers.CharField(label='名字', max_length=20)
gender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性別', required=False)
description = serializers.CharField(label='描述信息', max_length=200, required=False, allow_null=True)
# 詳見 下方的 外鍵:
# book = serializers.PrimaryKeyRelatedField(read_only=True)
# book = serializers.PrimaryKeyRelatedField(queryset=BookInfo.objects.all())
# book = serializers.StringRelatedField()
book = BookInfoSerializer()
2. 設(shè)置 隱藏字段
- 獲取書籍包含的 所有 相關(guān)人物 有 多個(gè), 需要添加參數(shù) many=True
peopleinfo_set = serializers.StringRelatedField(many=True)
3. 序列化器的外鍵 配置
3.1 外鍵兩種方法顯示: <模型對(duì)象> -> 顯示 模型對(duì)象id
# 1.1 需設(shè)置 read_only=True, 即 不能 通過此 參數(shù) 存入 book數(shù)據(jù) 到數(shù)據(jù)庫(kù)
book = serializers.PrimaryKeyRelatedField(read_only=True)
或
# 1.2 將 相關(guān) 數(shù)據(jù) 都給予 queryset
book = serializers.PrimaryKeyRelatedField(queryset=BookInfo.objects.all())
- 包含read_only=True參數(shù)時(shí)枉圃,該字段將不能用作反序列化使用
- 包含queryset參數(shù)時(shí)功茴,將被用作反序列化時(shí)參數(shù)校驗(yàn)使用
3.2 外鍵顯示: <模型對(duì)象> -> 顯示 __str__ 指定的 字符串
# 2. StringRelatedField 指向了 模型所對(duì)應(yīng)的 __str__ 方法
book = serializers.StringRelatedField()
3.3 外鍵顯示: <模型對(duì)象> -> 顯示<對(duì)象模型>所有屬性參數(shù)
# 3. 使用關(guān)聯(lián)對(duì)象的序列化器
book = BookInfoSerializer() # 相當(dāng)于 把 <book對(duì)象模型> 給予了 BookInfoSerializer 這個(gè)序列化器
4. 測(cè)試
4.1 序列化
- 從數(shù)據(jù)庫(kù)獲取對(duì)象
person = PeopleInfo.objects.get(id=1)
- 將對(duì)象 傳給 序列化器
serializer = PeopleInfoSerializer(person)
- 獲取序列化數(shù)據(jù)
serializer.data
{
'id': 1,
'name': '郭靖',
'gender': 1,
'description': '降龍十八掌',
'book': OrderedDict([
('id', 1),
('name', '射雕英雄傳'),
('pub_date', '1980-05-01'),
('readcount',12),
('commentcount', 34),
('is_delete', False),
('image', None),
('peopleinfo_set', ['郭靖', '黃蓉', '黃藥師', '歐陽鋒', '梅超風(fēng)'])
])
}
4.2 反序列化
4.2.1 數(shù)據(jù)校驗(yàn)(在終端執(zhí)行 python manage.py shell,進(jìn)行驗(yàn)證)
- 導(dǎo)入序列化器
from books.serializers import BookInfoSerializer
- 假擬 一個(gè) 前端 傳來的 數(shù)據(jù) data
data = {
'name': 'itcast',
'pub_date':'abdc',
'commentcount':20,
'readcount':50
}
- data: 把 前端 傳來的數(shù)據(jù) 給 序列化器
serializer = BookInfoSerializer(data=data)
- 校驗(yàn)數(shù)據(jù)
# 驗(yàn)證成功返回 True,否則返回 False
serializer.is_valid()
# 顯示報(bào)錯(cuò)信息
serializer.errors # 顯示報(bào)錯(cuò)信息
'''
參數(shù): raise_exception=True
在驗(yàn)證失敗時(shí)拋出異常serializers.ValidationError,
REST framework接收到此異常孽亲,會(huì)向前端返回HTTP 400 Bad Request響應(yīng)坎穿。
'''
serializer.is_valid(raise_exception=True)
4.2.2 三種自定義驗(yàn)證的方法(在 要驗(yàn)證的類里 定義 方法)
- 單個(gè)字段 個(gè)性化驗(yàn)證 (記得 返回 value)
class BookInfoSerializer(serializers.Serializer):
'''省略'''
def validate_readcount(self, value): # validate_要驗(yàn)證的字段名
if value < 0:
raise serializers.ValidationError("數(shù)據(jù)不能小于0")
return value # 記得 返回 value
- 多個(gè)字段 之間的驗(yàn)證 (記得 返回 attrs)
class BookInfoSerializer(serializers.Serializer):
'''省略'''
def validate(self, attrs):
# attrs 就是 那個(gè) data
# serializer = BookInfoSerializer(data=data)
# 即 attrs = data
commentcount = attrs.get("commentcount")
readcount = attrs.get("readcount")
if readcount < commentcount:
raise serializers.ValidationError('評(píng)論量,不能大于閱讀量')
return attrs # 記得 返回 attrs
- validators自定義驗(yàn)證 的使用 (記得在 對(duì)應(yīng)屬性 通過validators=[custom_validate] 調(diào)用)
class BookInfoSerializer(serializers.Serializer):
'''省略, 使用場(chǎng)景: 禁止 用戶 用 "admin" 這個(gè)用戶名 注冊(cè)'''
# 誰調(diào)用這個(gè)函數(shù)方法, self 就是誰,
# 這里 name 對(duì) 它 進(jìn)行了 調(diào)用 所以 這里的self 就是 name
def custom_validate(self):
if self == "admin":
raise serializers.ValidationError('請(qǐng)不要使用admin來注冊(cè)')
# 調(diào)用: validators 定義 name 采用 自定義的函數(shù)方法 custom_validate 驗(yàn)證
name = serializers.CharField(max_length=20, label='名字',validators=[custom_validate])
4.2.3 serializer.save() 入庫(kù)保存
- 創(chuàng)建 create 方法, 實(shí)現(xiàn) save() 的使用
(Serializer不具有.save需要的create()方法, 需要自行創(chuàng)建)
class BookInfoSerializer(serializers.Serializer):
'''
1. 當(dāng)我們的序列化器繼承自 serializer.Serializer的時(shí)候
2. 當(dāng)我們需要自己實(shí)現(xiàn) 序列化器的 create 方法, 實(shí)現(xiàn)create方法的目的: 實(shí)現(xiàn) 數(shù)據(jù)的保存操作
'''
def create(self, validated_data):
# validated_data
# 驗(yàn)證之后的數(shù)據(jù)
# 如果 我們?cè)谛蛄谢鞒跏蓟臅r(shí)候 傳遞的 data, 經(jīng)過我們的校驗(yàn)之后
# 完全符合驗(yàn)證規(guī)則時(shí) 那么 validated_data = data
"""
validated_data = {
'name': 'ppx',
'pub_date': 'abdc',
'commentcount': 2,
'readcount': 10
}
"""
book = BookInfo.objects.create(**validated_data) # 利用 解包, 傳入對(duì)應(yīng)的鍵值對(duì)
return book # 記得必須返回 book對(duì)象
- 注意: 寫入數(shù)據(jù)庫(kù)前 必須先驗(yàn)證, 否則會(huì)報(bào)錯(cuò) (在終端執(zhí)行 python manage.py shell,進(jìn)行驗(yàn)證)
from books.serializers import BookInfoSerializer
from books.models import BookInfo
data = {
'name': 'python',
'pub_date': '1998-12-22',
'commentcount': 2,
'readcount': 10
}
serializer = BookInfoSerializer(data=data) # 調(diào)用 序列化器, 進(jìn)行 反序列化
serializer.is_valid() # 校驗(yàn) 參數(shù)
serializer.save() # 保存 數(shù)據(jù) 到數(shù)據(jù)庫(kù)
- 創(chuàng)建 update() 方法, 實(shí)現(xiàn)執(zhí)行 serializer.save() 進(jìn)行更新操作
(Serializer不具有serializer.save()需要的update()方法, 需要自行創(chuàng)建)
class BookInfoSerializer(serializers.Serializer):
'''省略'''
def update(self, instance, validated_data):
# instance 序列化器中 初始化傳遞過來的模型對(duì)象
# validated_data:
# 如果我們?cè)谛蛄谢鞒跏蓟臅r(shí)候 傳遞的 data, 經(jīng)過我們的驗(yàn)證之后
# 完全符合驗(yàn)證規(guī)則的時(shí)候, validated_data = data
instance.name = validated_data.get('name', instance.name)
instance.pub_date = validated_data.get('pub_date', instance.pub_date)
instance.readcount = validated_data.get('readcount', instance.readcount)
instance.commentcount = validated_data.get('commentcount', instance.commentcount)
# 模型的數(shù)據(jù)發(fā)生變化后, 需要調(diào)用模型對(duì)象的 save 方法
instance.save()
# 更新數(shù)據(jù)完成之后 要返回 實(shí)例對(duì)象
return instance
在終端執(zhí)行 python manage.py shell,進(jìn)行驗(yàn)證
data = {
"id":1,
'name': 'ppx',
'pub_date': 'abdc',
'commentcount': 2,
'readcount': 10
}
book = BookInfo.objects.get(id=data.get("id")) # 通過前端 傳過來的 書籍id, 獲取書籍對(duì)象
# 同時(shí)傳入instance和data 即視為 更新操作
serializer = BookInfoSerializer(instance=book, data=data)
serializer.is_valid() # 校驗(yàn)參數(shù)
serializer.save() # 保存數(shù)據(jù)
兩點(diǎn)說明:
1) 在對(duì)序列化器進(jìn)行save()保存時(shí),可以額外傳遞數(shù)據(jù)墨林,這些數(shù)據(jù)可以在create()和update()中的validated_data參數(shù)獲取到
serializer.save(owner=request.user)
2)默認(rèn)序列化器必須傳遞所有required的字段赁酝,否則會(huì)拋出驗(yàn)證異常。但是我們可以使用partial參數(shù)來允許部分字段更新
serializer = BookInfoSerializer(instance=book, data={'pub_date': '2999-1-1'}, partial=True)
5. 使用ModelSerializer – 繼承自 類Serializer
5.1在 serializer.py模塊 新建 對(duì)應(yīng)序列化器類 繼承類ModelSerializer
劃重點(diǎn) :關(guān)聯(lián)模型類
model = BookInfo !
model = BookInfo !
model = BookInfo !
是關(guān)聯(lián) <模型類>, 不是 <查詢集> 不是BookInfo.query.all() # 大兄弟...!!!
'''
ModelSerializer 和 Serializer 的區(qū)別
1. ModelSerializer 是繼承自 Serializer
2. ModelSerializer 自動(dòng)幫我們 生成字段(根據(jù)模型類自動(dòng)生成)
3. ModelSerializer 自動(dòng)幫我們 實(shí)現(xiàn)了 create()方法 和 update()方法
4. ModelSerializer 必須 有 model
'''
from rest_framework import serializers
from books.models import BookInfo
class BookInfoModelSerializer(serializers.ModelSerializer):
class Meta:
# 1. 關(guān)聯(lián)模型類
model = BookInfo
# 2. # 默認(rèn)為 模型所有字段
fields = '__all__'
# 3. 自定義顯示指定某些字段
# fields = ['id', 'name', 'pub_date']
# 4. 不包含 某些字段
exclude = ['is_delete']
# 5. 修改自動(dòng)生成字段的 選項(xiàng) 信息
extra_kwargs= {
# 字段名: {選項(xiàng): 選項(xiàng)值}
'pub_date': {'required': True},
'readcount': {
'max_value': 100,
'min_value': 1
}
}
# 6. 設(shè)置以下這些字段為只讀屬性
# read_only_fields = ['id', 'name', 'pub_date']
- 注意: 修改屬性, 都是在 class Meta: 里面寫的 model旭等、 fields酌呆、exclude、extra_kwargs搔耕、read_only_fields