drf-序列化器的理解

序列化器做用: 
1.進行數據的校驗
2.對數據對象進行轉換
序列化:  模型類對象  ----->  python字典    用於輸出, 返回給前端使用
反序列化:  前端傳送的數據  -------> 通過驗證 -----> python的字典   用於輸入  接受前端數據時使用
序列化器做用: 幫助咱們進行序列化, 反序列化
總結 :
在開發REST API接口時,咱們在視圖中須要作的最核心的事是:
將數據庫數據序列化爲前端所須要的格式,並返回; 
將前端發送的數據反序列化爲模型類對象,並保存到數據庫中
在開發REST API的視圖中,雖然每一個視圖具體操做的數據不一樣,但增、刪、改、查的實現流程基本套路化,因此這部分代碼也是能夠複用簡化編寫的:
增:校驗請求數據 -> 執行反序列化過程 -> 保存數據庫 -> 將保存的對象序列化並返回
刪:判斷要刪除的數據是否存在 -> 執行數據庫刪除
改:判斷要修改的數據是否存在 -> 校驗請求的數據 -> 執行反序列化過程 -> 保存數據庫 -> 將保存的對象序列化並返回
查:查詢數據庫 -> 將數據序列化並返回
1.序列化的定義
根據模型類定義序列化器
示例:
模型類
class BookInfo(models.Model):
    btitle = models.CharField(max_length=20, verbose_name='名稱')
    bpub_date = models.DateField(verbose_name='發佈日期', null=True)
    bread = models.IntegerField(default=0, verbose_name='閱讀量')
    bcomment = models.IntegerField(default=0, verbose_name='評論量')
    image = models.ImageField(upload_to='booktest', verbose_name='圖片', null=True)

class BookInfoSerializer(serializers.Serializer):
    """圖書數據序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True) # read_only只在序列化中使用, 反序列化不使用
    # write_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)
序列化:  模型類對象  ----->  python字典    用於輸出, 返回給前端使用
反序列化:  前端傳送的數據  -------> 通過驗證 ----->save python的字典   用於輸入  接受前端數據時使用
序列化器做用: 幫助咱們進行序列化, 反序列化
注意: serializer不是隻能爲數據庫模型類定義,也能夠爲非數據庫模型類的數據定義
 
2. 建立serializer對象
定義好Serializer類後,就能夠建立Serializer對象了。
Serializer的構造方法爲:
 
Serializer(instance=None, data=empty, **kwarg)
 
說明:
1)用於序列化時,將模型類對象傳入instance參數
2)用於反序列化時,獲取數據前進行驗證 (  is_valid()   ),  將要被反序列化的數據傳入data參數
3)除了instance和data參數外,在構造Serializer對象時,還可經過context參數額外添加數據,如
 
 serializer = AccountSerializer(account, context={'request': request})
 
經過context參數附加的數據,能夠經過Serializer對象的context屬性獲取。
3. 序列化的使用
1. 基本使用
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')])]
 
2. 關聯對象
1) PrimaryKeyRelatedField
此字段將被序列化爲關聯對象的主鍵。
 
hbook = serializers.PrimaryKeyRelatedField(label='圖書', read_only=True)
或
hbook = serializers.PrimaryKeyRelatedField(label='圖書', queryset=BookInfo.objects.all())
 
指明字段時須要包含read_only=True或者queryset參數:
 
包含read_only=True參數時,該字段將不能用做反序列化使用
包含queryset參數時,將被用做反序列化時參數校驗使用查詢
 
4. 反序列化的使用
 1. 驗證
在獲取反序列化的數據前,必須調用 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)
 
2.保存
若是在驗證成功後,想要基於validated_data完成數據對象的建立,能夠經過實現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參數獲取到
 
serializer.save(owner=request.user)
 
2)默認序列化器必須傳遞全部required的字段,不然會拋出驗證異常。可是咱們能夠使用partial參數來容許部分字段更新
 
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
5. 模型類serializers
ModelSerializer與常規的Serializer相同,但提供了:
基於模型類自動生成一系列字段      #  自動生成字段
基於模型類自動爲Serializer生成validators,好比unique_together         # 惟一約束
包含默認的create()和update()的實現             #  默認的兩種方法
 
1. 定義
demo
 
class BookInfoSerializer(serializers.ModelSerializer):
    """圖書數據序列化器"""
    class Meta:   # Meta是一個內部類,它用於定義一些Django模型類的行爲特性
        model = BookInfo
        fields = '__all__'
model 指明參照哪一個模型類
fields 指明爲模型類的哪些字段生成
 
2. 指定字段
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) 默認ModelSerializer使用主鍵做爲關聯字段,可是咱們能夠使用depth來簡單的生成嵌套表示,depth應該是整數,代表嵌套的層級數量。如:
 
class HeroInfoSerializer2(serializers.ModelSerializer):
    class Meta:
        model = HeroInfo
        fields = '__all__'
        depth = 1
 
造成的序列化器以下:
 
HeroInfoSerializer():
    id = IntegerField(label='ID', read_only=True)
    hname = CharField(label='名稱', max_length=20)
    hgender = ChoiceField(choices=((0, 'male'), (1, 'female')), label='性別', required=False, validators=[<django.core.valators.MinValueValidator object>, <django.core.validators.MaxValueValidator object>])
    hcomment = CharField(allow_null=True, label='描述信息', max_length=200, required=False)
    hbook = NestedSerializer(read_only=True):
    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)
 
4) 顯示指明字段,如:
 
class HeroInfoSerializer(serializers.ModelSerializer):
    hbook = BookInfoSerializer()
    class Meta:
        model = HeroInfo
        fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')
 
5) 指明只讀字段
 
能夠經過 read_only_fields指明只讀字段,即僅用於序列化輸出的字段
 
class BookInfoSerializer(serializers.ModelSerializer):
    """圖書數據序列化器"""
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
        read_only_fields = ('id', 'bread', 'bcomment')
 
3. 添加額外參數
咱們能夠使用extra_kwargs參數爲ModelSerializer添加或修改原有的選項參數
 
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='閱讀量', min_value=2147483647, min_value=0, required=True)
 
 
# bcomment = IntegerField(label='評論量', min_value=2147483647, min_value=0, required=True)
相關文章
相關標籤/搜索