drf—— 序列化組件

----->序列化器-Serializer

1、序列化組件介紹

#做用:
    1. 序列化,序列化器會把模型對象轉換成字典,通過response之後變成json字符串
        -Book模型--序列化器--->字典--經過drf:Response--》json格式字符串--->傳給前端
    2. 反序列化,把客戶端發送過來的數據,通過request之後變成字典,序列化器能夠把字典轉成模型
        json格式數據---經過drf:Request-->字典---序列化器---》Book模型
    3. 反序列化,完成數據校驗功能

2、序列化組件簡單使用

# 序列化的使用
    -寫一個序列化類繼承serializers.Serializer
    -在類中寫要序列化的字段
    -在視圖類中,實例化獲得一個序列化類的對象,把要序列化的數據傳入
        ser=BookSerializer(instance=res,many=True)
    -獲得字典
        ser.data就是序列化後的字典

3、序列化組件使用代碼實現

'''
5個接口 1. 查詢全部 Book--》get 2. 查詢單個 BookDetali--》get 3. 新增一個 Book--》post 4. 刪除一個 BookDetali--》delete 5. 修改一個 BookDetali--》put '''

1.查詢全部

url:127.0.0.1.8000/books/  # 注意最後面的 /必定要寫

 

 models.py  # 創建好模型,進行數據遷移,在數據庫中手動添加至少2條數據前端

from django.db import models

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32,null=True) #測試read_only
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.CharField(max_length=32)

urls.py   #配置好路由python

path('books/', views.Book.as_view()),

views.py  #寫視圖類git

from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
from app01.serializer import BookSerializer

class Book(APIView):
    def get(self, request, *args, **kwargs):
        res = models.Book.objects.all()
        # 藉助序列化器
        # 若是是多條,就是many=True
        # 若是是單個對象,就不寫
        ser = BookSerializer(instance=res, many=True)
        print(type(ser))  # rest_framework.serializers.ListSerializer
        # 經過序列化器獲得的字典
        # ser.data
        print(ser.data)
        return Response(ser.data)

serializer.py  #在app中建立存放序列化器的 類的文件 serializer.py 並寫BookSerializer類數據庫

# 序列化器類(序列化Book表)
# from rest_framework.serializers import Serializer
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01 import models


class BookSerializer(serializers.Serializer):
    # 要序列化哪一個字段
    id = serializers.IntegerField(required=False)
    # id=serializers.CharField()
    title = serializers.CharField(max_length=32,min_length=2,read_only=True)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    # 序列化的時候看不到,由於write_only=True
   publish = serializers.CharField(max_length=32,write_only=True)

2.查詢單個

url:127.0.0.1.8000/books/1 #後面的數字表明查詢id爲幾的數據 

urls.py中加django

re_path('^books/(?P<id>\d+)', views.BookDetail.as_view()),

views.py中加json

class BookDetail(APIView):
    def get(self, request, id):
        res = models.Book.objects.all().filter(id=id).first()
        # 單個,去掉many=True
        # 加many=True和不加,ser不是同一個對象,查單個是BookSerializer對象,查多個是ListSerializer對象,這是由源碼中元類決定的
        ser = BookSerializer(instance=res)
        print(type(ser))  # 打印出 app01.serializer.BookSerializer
        return Response(ser.data)

3.新增一個  ---這裏涉及到保存!!!

ps:新增必須寫create方法app

urls.py 不變源碼分析

views.pypost

class Book(APIView):
    def get(self, request, *args, **kwargs):
        ...

    def post(self, request):
        # post提交的數據都在request.data 是個字典
        print(request.data)
        ser = BookSerializer(data=request.data)
        if ser.is_valid():  # 校驗數據是否合法
            ser.save()  # 保存到數據庫中
            return Response(ser.data)
        else:
            # 沒有校驗經過的錯誤信息
            return Response(ser.errors)
serializer.py
# 若是序列化類繼承的是Serializer,必須重寫create方法

class BookSerializer(serializers.Serializer):
    ...
    def create(self, validated_data):
        # 爲何要重寫create?爲了跟views.py裏面的Book表創建關係
        res=models.Book.objects.create(**validated_data)
        print(res)
        return res

4.修改

ps:必須寫update方法測試

urls.py不變

views.py

class BookDetail(APIView):
    def get(self, request, id):
        ...

    def put(self, request, id):
        # 經過id取到對象
        res = {'code': 100, 'msg': ''}
        try:
            book = models.Book.objects.get(id=id)
            ser = BookSerializer(instance=book, data=request.data)
            ser.is_valid(raise_exception=True)
            ser.save()
            res['msg'] = '修改爲功'
            res['result'] = ser.data

        except Exception as e:
            res['code'] = 101
            res['msg'] = str(e)

        return Response(res)
serializer.py
class BookSerializer(serializers.Serializer):
    ...

    def update(self, book, validated_data):
        book.title=validated_data.get('title')
        book.price=validated_data.get('price')
        book.publish=validated_data.get('publish')
        book.save()
        return book

5.刪除

views.py

class BookDetail(APIView):
    ...

    def delete(self,request,id):
        response = {'code': 100, 'msg': '刪除成功'}
        models.Book.objects.filter(id=id).delete()
        return Response(response)

 

4、序列化類字段類型和字段參數

# 經常使用字段類型
    -IntegerField
    -CharField
    -DecimalField
    -DateTimeField
    -。。。跟models中大差不差
    
# 經常使用字段參數
    -選項參數
        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    包含錯誤編號與錯誤信息的字典

---------------------序列化器-------------------------

5、序列化器的(反序列化之)保存功能

同三中3.增長一個 裏面的保存

6、序列化器的(反序列化之)字段校驗功能

 validators校驗,局部鉤子,全局鉤子

ps:validators 列表裏面能夠傳多個值進行校驗

# 三種方式
    -字段本身的校驗規則(max_length...)
    -validators的校驗
        publish = serializers.CharField(max_length=32,validators=[check,])

        def check(data):
        if len(data)>10:
            raise ValidationError('最長不能超過10')
        else:
            return data
    -局部和全局鉤子
        # 局部鉤子,validate_字段名,須要帶一個data,data就是該字段的數據
    def validate_title(self, data):
        if data.startswith('sb'):
            raise ValidationError('不能以sb開頭')
        else:
            return data
    # 全局鉤子
    def validate(self, attrs):
        title=attrs.get('title')
        publish=attrs.get('publish')
        if title==publish:
            raise ValidationError('書名不能跟出版社同名')
        else:
            return attrs

7、序列化類經常使用字段參數之read_only和write_only

   read_only    代表該字段僅用於序列化輸出,默認False
    write_only    代表該字段僅用於反序列化輸入,默認False
    
    
    class BookSerializer(serializers.Serializer):
        # 要序列化哪一個字段
        id = serializers.IntegerField(required=False)
        # id=serializers.CharField()
        title = serializers.CharField(max_length=32,min_length=2,read_only=True)
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
        # 序列化的時候看不到
        publish = serializers.CharField(max_length=32,validators=[check,],write_only=True)

 8、(反序列化之高級用法之source

總結:

1用法一: 修改返回到前端的字段名
    # 若source=title 那麼字段名就不能再叫title,這裏叫了name
    name = serializers.CharField(max_length=32,min_length=2,source='title')
2用法二: 若是表模型中有方法
class Book(models.Model):
    ...
    def test(self):
        # python是強類型語言,不支持字符串和數字直接相加
        return self.title+str(self.price)
    # 執行表模型中的test方法,而且把返回值賦值給xxx
    xxx=serializers.CharField(source='test')
3用法三: source支持跨表操做
    addr=serializers.CharField(source='publish.addr')
    
# 能夠去看源碼,內部如何實現的

代碼:

urls.py

models.py

from django.db import models

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32,null=True) #測試read_only
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # publish = models.CharField(max_length=32)
    #修改後
    publish = models.ForeignKey(to='Publish',null=True,on_delete=models.CASCADE)
    #這是在測試source第一種方法時加的
    def test(self):
        # python是強類型語言,不支持字符串和數字直接相加
        return self.title+str(self.price)

#新建一張publish表
class Publish(models.Model):
    name=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)
    #重寫__str__
    def __str__(self):
        return self.name

views.py

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
#方法一
    name = serializers.CharField(max_length=32,min_length=2,source='title')
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
#方法三,要直接顯示出publish的名字 ,或 在models.py中重寫__str__   
publish = serializers.CharField(max_length=32,source='publish.name')
#方法二
    xxx=serializers.CharField(source='test')
#方法三:跨表
    publish_addr=serializers.CharField(source='publish.addr')

9、模型類序列化器

1 原來用的Serilizer跟表模型沒有直接聯繫, 模型類序列化器ModelSerilizer,跟表模型有對應關係

2 使用
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model=表模型    # 跟哪一個表模型創建關係
            fields=[字段,字段] # 序列化的字段,反序列化的字段
            fields='__all__' # 全部字段都序列化,反序列化
            exclude=[字段,字段] # 排除哪些字段(不能跟fields同時使用)
            read_only_fields=['price','publish']  # 序列化顯示的字段
            write_only_fields=['title']           # 反序列化須要傳入的字段
            extra_kwargs ={'title':{'max_length':32,'write_only':True}}
            depth=1  # 瞭解,跨表1查詢,最多建議寫3
        # 重寫某些字段
        publish = serializers.CharField(max_length=32,source='publish.name')
        # 局部鉤子,全局鉤子,跟原來徹底同樣
3 新增,修改
    -通通不用重寫create和update方法了,在ModelSerializer中重寫了create和update

10、(反序列化之)高級用法之SerializerMethodField

 

#方式一:Serializer
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    name = serializers.CharField(max_length=32,min_length=2,source='title')
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    publish = serializers.SerializerMethodField()
    def get_publish(self,obj):
        dic={'name':obj.publish.name,'addr':obj.publish.addr}
        return dic

#方式二:ModelSerializer
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = '__all__'
    publish = serializers.SerializerMethodField()
    def get_publish(self,obj):
        dic={'name':obj.publish.name,'addr':obj.publish.addr}
        return dic
    
    
  
# 方式三:使用序列化類的嵌套
class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        # fields = '__all__'
        fields = ['name','addr']


class BookModelSerializer(serializers.ModelSerializer):
    publish = PublishSerializer()

    class Meta:
        model = models.Book
        fields = '__all__'

11、序列化組件源碼分析

#序列化組件,先調用__new__方法,若是many=True,生成ListSerializer對象,若是爲False,生成Serializer對象
#序列化對象.data方法--調用父類data方法---調用對象本身的to_representation(自定義的序列化類無此方法,去父類找)
#Aerializer類裏有to_representation方法,for循環執行attribute = field.get_attribute(instance)
#再去Field類裏去找get_attribute方法,self.source_attrs就是被切分的source,而後執行get_attribute方法,source_attrs
#當參數傳過去,判斷是方法就加括號執行,是屬性就把值取出來
相關文章
相關標籤/搜索