1. 程式人生 > 實用技巧 >序列化元件serializer基本使用

序列化元件serializer基本使用

目錄

1. 序列化元件使用原理

  1. 序列化,序列化器會把模型物件轉換成字典,經過response以後變成json字串
  2. 反序列化,把客戶端傳送過來的資料,經過request以後變成字典,序列化器可以把字典轉成模型
  3. 反序列化,完成資料校驗功能

2. 序列化元件serializer的簡單使用

  • 寫一個序列化類

  • 在類中寫要序列化的欄位,想序列化哪個欄位,就在類中寫哪個欄位

  • 在檢視類中匯入該序列化類,例項化序列化類得到序列化類的物件,將需要序列化的物件傳入

  • 序列化類的物件.data 是一個字典

  • 把字典返回,如果不使用rest_framework提供的Response,就得使用JsonResponse

3.序列化元件使用 --- 序列化之查詢指定id書籍的介面

  • 準備書籍表
from django.db import models


class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish = models.CharField(max_length=32)

  • 建立任意名稱的py檔案,在該檔案中建立序列化類,該序列化類需要繼承APIView
from rest_framework.views import APIView
from rest_framework import seriaizers

class BookSerializer(serializers.Serializer):
    id = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()
  • 在views.py中建立檢視類,並使用自定義的序列化類對資料進行序列化,使用rest_framework的Response返回資料
from app01.ser import BookSerializer
from app01 import models


class BookView(APIView):
    def get(self,request,pk):
        dic = {'code':100,'status':'成功'}
        book = models.Book.objects.filter(pk=pk).first()
        book_ser = BookSerializer(book)
        dic['data'] = book_ser.data
        return Response(dic)
  • 在urls.py中寫好路由與檢視類的對應關係
re_path(r'^book/(?P<pk>\d+)',views.BookView.as_view()),

4. 序列化元件使用---反序列化之修改資料

  • 需要在序列化類中定義校驗規則,如果客戶端返回給後端的資料符合校驗規則,就需要將資料儲存到資料庫,當資料通過校驗的時候,如果不在序列化類中重寫update方法就會丟擲異常
# 序列化類檔案
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

# 校驗規則也可以寫在序列化類的外面,哪個欄位需要這個校驗規則就加入到哪個欄位的後面,使用validators=[check_book,]的格式
def check_book(data):
    # data是瀏覽器客戶端傳過來的對應的欄位的資料,因為該方法加在了name欄位後面,所以data就是瀏覽器傳到後端的name
    print(data)
    
    
class BookSerializer(serializers.Serializer):
    id = serializers.CharField(read_only=True)
    name = serializers.CharField(validators=[check_book,])
    price = serializers.CharField()
    publish = serializers.CharField()
    # 區域性校驗,適用於單個欄位
    def validate_name(self, instance):
        # instance是瀏覽器返回的要修改的資料
        if instance.startswith('xxx'):
            raise ValidationError('不能以xxx開頭')
        else:
            return instance
    # 全域性校驗,適用於多個欄位的校驗
    def validate(self, attrs):
        # attrs是客戶端要返回給後端的資料物件
        if attrs.get('name') == attrs.get('publish'):
            raise ValidationError('二者不能相同')
        else:
            return attrs
    # 重寫update方法
    def update(self, instance, validated_data):
        '''
        :param instance: 修改的物件
        :param validated_data: 更新的資料
        :return:
        '''
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        return instance
    
# 檢視檔案
class BookView(APIView):
    。...

    def put(self,request,pk):
        dic = {'code':100,'status':''}
        book = models.Book.objects.filter(pk=pk).first()
        # instance是修改的物件,data是瀏覽器客戶端返回的資料
        book_ser = BookSerializer(instance=book,data=request.data)
        # 判斷資料是否通過校驗
        if book_ser.is_valid():
            # 如果資料通過校驗就需要在序列化類中重寫update方法
            book_ser.save()
            dic['status'] = '修改成功'
            dic['data'] = book_ser.data
        else:
            dic['status'] = '修改失敗'
            dic['data'] = book_ser.errors
        return Response(dic)

5. 刪除資料

刪除資料無需使用序列化元件

def delete(self,request,pk):
    dic = {'code':100,'status':''}
    book = models.Book.objects.filter(pk=pk).delete()
    dic['status'] = '刪除成功'
    return Response(dic)

6. 序列化查詢所有所有書籍

在序列化資料的時候,需要指定many=True,因為查到的資料是多條

def get(self,request):
    books = models.Book.objects.all()
    book_ser = BookSerializer(books,many=True)
    return Response(book_ser.data)

7. 反序列化 --- 新增書籍

新增書籍需要通過序列化類的校驗,並且需要重寫create方法

# 序列化類
    # 重寫update方法
    def update(self, instance, validated_data):
        '''
        :param instance: 修改的物件
        :param validated_data: 更新的資料
        :return:
        '''
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        return instance

    def create(self,validated_data):
        # 客戶端新增的資料是一個字典
        print(validated_data)
        instance = models.Book.objects.create(**validated_data)
        return instance
    
    # views.py
    def post(self,request):
        # 增加資料,data是客戶端返回給服務端的使用者資料物件
        dic = {'code':100,'status':''}
        book_ser = BookSerializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            book_ser.save()
            dic['data'] = book_ser.data
        else:
            dic['data'] = book_ser.errors
        return Response(dic)

8. 模型類序列化器

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=Book  # 對應上models.py中的模型
        fields='__all__'  # models中的所有欄位
        # fields=('name','price','id','author') # 只序列化指定的欄位
        # exclude=('name',) #跟fields不能都寫,寫誰,就表示排除誰
        # read_only_fields=('price',)
        # write_only_fields=('id',) #棄用了,使用extra_kwargs
        extra_kwargs = {  # 類似於這種形式name=serializers.CharField(max_length=16,min_length=4)
            'price': {'write_only': True},
        }
        
# 其他使用一模一樣
#不需要重寫create和updata方法了

9. many=True的原始碼分析

序列化多條資料的時候需要傳many=True。

book_ser=BookModelSerializer(books,many=True)
book_one_ser=BookModelSerializer(book)
print(type(book_ser))
#<class 'rest_framework.serializers.ListSerializer'>
print(type(book_one_ser))
#<class 'app01.ser.BookModelSerializer'>

'''
物件的生成--》先呼叫類的__new__方法,生成空物件
物件=類名(name=lqz),觸發類的__init__()
類的__new__方法控制物件的生成
'''
def __new__(cls, *args, **kwargs):
    if kwargs.pop('many', False):
        return cls.many_init(*args, **kwargs)
    # 沒有傳many=True,走下面,正常的物件例項化
    return super().__new__(cls, *args, **kwargs)

10. Serializer高階用法

# source的使用
	1 可以改欄位名字  xxx=serializers.CharField(source='title')
    2 可以.跨表publish=serializers.CharField(source='publish.email')
    3 可以執行models表中的方法pub_date=serializers.CharField(source='test') test是Book表模型中的方法
    

# SerializerMethodField()的使用,當表關係是多對多的關係的欄位
	它需要有個配套方法,方法名叫get_欄位名,返回值就是要顯示的東西
    authors=serializers.SerializerMethodField() #它需要有個配套方法,方法名叫get_欄位名,返回值就是要被序列化的資料
    def get_authors(self,instance):
        # book物件
        authors=instance.authors.all()  # 取出所有作者
        l = []
        for author in authors:
            l.append({'name':author.name,'age':author.age})
        return l

11. 簡單封裝Response物件返回的狀態碼資訊

class MyResponse():
    def __init__(self):
        self.status=100
        self.msg='成功'
    @property
    def get_dict(self):
        return self.__dict__

if __name__ == '__main__':
    res=MyResponse()
    res.status=101
    res.msg='查詢失敗'
    # res.data={'name':'lqz'}
    print(res.get_dict)

補充

  • 序列化類的欄位型別
欄位 欄位構造方式
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) 正則欄位,驗證正則模式 [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: 最多位數 decimal_palces: 小數點位置
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=)
  • 序列化欄位選項引數
引數名稱 作用
max_length 最大長度
min_lenght 最小長度
allow_blank 是否允許為空
trim_whitespace 是否截斷空白字元
max_value 最小值
min_value 最大值
  • 序列化欄位通用引數
引數名稱 說明
read_only 表明該欄位僅用於序列化輸出,預設False,如果設定成True,postman中可以看到該欄位,修改資料時不需要傳該欄位
write_only 表明該欄位僅用於反序列化輸入,預設False,如果設定成True,postman中看不到該欄位,修改時,該欄位需要傳
required 表明該欄位在反序列化時必須輸入,預設True
default 反序列化時使用的預設值
allow_null 表明該欄位是否允許傳入None,預設False
validators 該欄位使用的驗證器
error_messages 包含錯誤編號與錯誤資訊的字典
label 用於HTML展示API頁面時,顯示的欄位名稱
help_text 用於HTML展示API頁面時,顯示的欄位幫助提示資訊