五冤荆、DRF之序列化器

寫在前面:

'''
序列化器:
實(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ù)保存
  1. 創(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ù)
  1. 創(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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隙袁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子弃榨,更是在濱河造成了極大的恐慌菩收,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鲸睛,死亡現(xiàn)場(chǎng)離奇詭異娜饵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)官辈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門箱舞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拳亿,你說我怎么就攤上這事晴股。” “怎么了肺魁?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵电湘,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)寂呛,這世上最難降的妖魔是什么怎诫? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮昧谊,結(jié)果婚禮上刽虹,老公的妹妹穿的比我還像新娘。我一直安慰自己呢诬,他們只是感情好涌哲,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著尚镰,像睡著了一般阀圾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狗唉,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天初烘,我揣著相機(jī)與錄音,去河邊找鬼分俯。 笑死肾筐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缸剪。 我是一名探鬼主播吗铐,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼杏节!你這毒婦竟也來了唬渗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤奋渔,失蹤者是張志新(化名)和其女友劉穎镊逝,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嫉鲸,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡撑蒜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了玄渗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片减江。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖捻爷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情份企,我是刑警寧澤也榄,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響甜紫,放射性物質(zhì)發(fā)生泄漏降宅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一囚霸、第九天 我趴在偏房一處隱蔽的房頂上張望腰根。 院中可真熱鬧,春花似錦拓型、人聲如沸额嘿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽册养。三九已至,卻和暖如春压固,著一層夾襖步出監(jiān)牢的瞬間球拦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工帐我, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坎炼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓拦键,卻偏偏與公主長(zhǎng)得像谣光,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矿咕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 介紹 本教程將涵蓋一個(gè)簡(jiǎn)單的PasteBin1代碼高亮的Web API抢肛。整個(gè)過程,將逐一介紹REST framew...
    盛夏_264f閱讀 524評(píng)論 0 0
  • Serializers 序列化器允許將諸如查詢集和模型實(shí)例之類的復(fù)雜數(shù)據(jù)轉(zhuǎn)換為原生 Python 數(shù)據(jù)類型碳柱,然后可...
    lkning閱讀 1,029評(píng)論 0 1
  • 創(chuàng)建一個(gè)應(yīng)用程序捡絮,用于創(chuàng)建簡(jiǎn)單的Web API。 python manage.py startapp snippe...
    nine_9閱讀 886評(píng)論 0 1
  • 模塊間聯(lián)系越多莲镣,其耦合性越強(qiáng)福稳,同時(shí)表明其獨(dú)立性越差( 降低耦合性,可以提高其獨(dú)立性)瑞侮。軟件設(shè)計(jì)中通常用耦合度和內(nèi)聚...
    riverstation閱讀 2,075評(píng)論 0 8
  • 從那以后 我怠惰散漫的活 苦苦掙扎于自己圍困的城 余生都無法逃離 所有的夙愿 滿懷的豪情 都化為了城中 小小的一粒...
    萬書閱讀 160評(píng)論 0 0