1. 程式人生 > 其它 >09 序列化器Serializer 與模型類序列化器ModelSerializer

09 序列化器Serializer 與模型類序列化器ModelSerializer

1 序列化器-Serializer

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

2 序列化器的序列化

2.1 基本使用

2.1.1 表模型 models.py

from django.db import models


# Create your models here.


class Book(models.Model):
    title = models.CharField(max_length=32,default='
') price = models.IntegerField(default='0') # pub_date = models.DateField() # sqlite對日期的處理有問題,換成mysql publish = models.CharField(max_length=32,default='')

2.1.2 路由urls.py

from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
    path(
'books/<int:pk>', views.BookDetailView.as_view()), ]

2.1.3 檢視層views.py

from django.shortcuts import render

# Create your views here.


# def test(request):
#     request.session['name']='lqz'


#### 查詢所有圖書的檢視類
from rest_framework.views import APIView
from app01.models import Book  # 絕對匯入

# from .models import Book  # 相對匯入,用了相對匯入,當前py檔案,不能以指令碼形式執行
from .serializer import BookSerializer from rest_framework.response import Response # 針對於某個表模型,總共5個介面 # 獲取所有 get # 獲取單個 get # 刪除單個 delete # 修改單個 update # 新增單個 post # 以後你寫的所有介面(跟資料庫相關),都是這個5個或這5個的變形 class BookView(APIView): def get(self, request, *args, **kwargs): # 查詢出所有圖書 books = Book.objects.all() # 把qs物件序列化成字典,使用序列化類完成序列化 # instance=None, 是要序列化的物件(可以是單個物件,可以是多個物件(放到列表或者qs物件),一定要寫many=True) # data=empty 反序列化的字典,目前還沒用到 print(books) ser = BookSerializer(instance=books, many=True) # 傳入要序列化的資料 print(ser.data) # 返回給前端 ser.data 是個字典 # 如果是瀏覽器,會有一個好看的頁面(註冊app),如果是postman,就是json格式 return Response(data=ser.data) # 新增 def post(self, request, *args, **kwargs): # 前端傳入的資料,在request.data中,是個字典 # 如果不使用序列化類,如何儲存 # book=Book(title=request.data.get('title')) # book.save() # 使用序列化類做儲存 ser = BookSerializer(data=request.data) # 資料校驗:如果是True,表示校驗通過,直接儲存 if ser.is_valid(): ser.save() # 呼叫儲存,但是有問題,儲存不了,一定要在序列化類中重寫某個方法 return Response(ser.data) # 又做了一次序列化,返回給了前端 else: return Response(ser.errors) class BookDetailView(APIView): def get(self, request, pk): # 查詢某一本圖書 books = Book.objects.all().filter(pk=pk).first() ser = BookSerializer(instance=books) # 傳入要序列化的資料 return Response(data=ser.data) def delete(self, request, pk): # 跟序列化類沒有關係 Book.objects.all().filter(pk=pk).delete() return Response() def put(self, request, pk): book = Book.objects.filter(pk=pk).first() ser = BookSerializer(instance=book, data=request.data) # 資料校驗:如果是True,表示校驗通過,直接儲存 if ser.is_valid(): ser.save() # 呼叫儲存,但是有問題,儲存不了,一定要在序列化類中重寫update方法 return Response(ser.data) # 又做了一次序列化,返回給了前端

2.1.4 序列化器serializer.py

# 寫序列化類
from rest_framework import serializers
from .models import Book
from rest_framework.exceptions import ValidationError


class BookSerializer(serializers.Serializer):  # 一定要繼承一個序列化的基類
    # 寫欄位,你想序列化哪個欄位,就寫哪個
    title = serializers.CharField(max_length=8, min_length=3)
    price = serializers.IntegerField()
    # pub_date = serializers.DateField()

    publish = serializers.CharField()

    # 重寫create,使它能夠支援新增儲存  (派生)
    def create(self, validated_data):  # validated_data校驗過後的資料
        book = Book.objects.create(**validated_data)
        return book  # 一定不要忘了return 物件,否則在檢視類中用ser.data 就報錯了

    # 重寫 update 支援修改
    def update(self, instance, validated_data):
        instance.title = validated_data.get('title')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()
        return instance

    # validate_欄位名     先走欄位自己的,再走區域性鉤子
    def validate_title(self, item):
        print(item)
        # 校驗欄位,不能以sb開頭
        if item.startswith('sb'):
            raise ValidationError('不能以sb開頭')

        return item

    # 全域性鉤子
    def validate(self, attrs):
        # 校驗失敗,拋異常
        if attrs.get('title') == attrs.get('publish'):
            raise ValidationError('標題和出版社不能一樣')

        return attrs

2.2 常用欄位

注意:serializer不是隻能為資料庫模型類定義,也可以為非資料庫模型類的資料定義。serializer是獨立於資料庫之外的存在。

常用欄位型別

2.3 常用欄位引數

選項引數:

通用引數:

3 序列化器的反序列化

3.1 基本使用(需要重寫create,update,見上面)

#新增
def post(self, request, *args, **kwargs): # 前端傳入的資料,在request.data中,是個字典 # 如果不使用序列化類,如何儲存 # book=Book(title=request.data.get('title')) # book.save() # 使用序列化類做儲存 ser = BookSerializer(data=request.data) # 資料校驗:如果是True,表示校驗通過,直接儲存 if ser.is_valid(): ser.save() # 呼叫儲存,但是有問題,儲存不了,一定要在序列化類中重寫某個方法 return Response(ser.data) # 又做了一次序列化,返回給了前端 else: return Response(ser.errors)
#修改
def
put(self, request, pk): book = Book.objects.filter(pk=pk).first() ser = BookSerializer(instance=book, data=request.data) # 資料校驗:如果是True,表示校驗通過,直接儲存 if ser.is_valid(): ser.save() # 呼叫儲存,但是有問題,儲存不了,一定要在序列化類中重寫update方法 return Response(ser.data) # 又做了一次序列化,返回給了前端

3.2 資料校驗

# 欄位自己校驗規則
title = serializers.CharField(max_length=8, min_length=3)

# 區域性鉤子
# validate_欄位名     先走欄位自己的,再走區域性鉤子
    def validate_title(self, item):
        print(item)
        # 校驗欄位,不能以sb開頭
        if item.startswith('sb'):
            raise ValidationError('不能以sb開頭')

        return item
# 全域性鉤子
    def validate(self, attrs):
        # 校驗失敗,拋異常
        if attrs.get('title') == attrs.get('publish'):
            raise ValidationError('標題和出版社不能一樣')

        return attrs

4 模型類序列化器ModelSerializer

 反序列化,正常情況不需要重寫 create和update 序列化:跟表模型有對應關係,不需要一個個欄位都寫了
# class BookModelSerializer(serializers.ModelSerializer):
#     # 跟某個表模型建立關係
#     class Meta:
#         model = Book  # 跟哪個表建立關係
#         fields = ['title','price','id','publish']  # 要序列化哪些欄位
#         # fields = '__all__'  # 所有欄位都序列化
#
#
#         # 瞭解
#         # exclude=['title']  # 除了某個欄位外
#         # depth=1            # 表關聯
#
#
#
#         #重點
#
#         # read_only  只讀,只序列化
#
#         # write_only
#
#     # 重寫某個欄位
#     title=serializers.CharField(max_length=8,min_length=3)
#
#     # 區域性和全域性鉤子跟之前一模一樣
#
#     def validate_price(self, price):
#         if not price>100:
#             raise ValidationError('價格必須大於100')
#
#         return price


class BookModelSerializer(serializers.ModelSerializer):
    # 跟某個表模型建立關係
    class Meta:
        model = Book  # 跟哪個表建立關係
        fields = ['title', 'price', 'id', 'publish']  # 要序列化哪些欄位
        # 重點
        # 額外給某些欄位傳引數
        # extra_kwargs = {
        #     'title': {'max_length': 8, 'min_length': 3},
        #     'price': {'min_value': 100}
        # }

        # read_only  只讀,只序列化
        # write_only 只寫,只做反序列化,這個欄位不做序列化
        extra_kwargs = {
            'title': {'read_only': True},
            # 'price': {'write_only': True}
        }