1. 程式人生 > >Django的序列化方法 Serializers 序列化元件

Django的序列化方法 Serializers 序列化元件

安裝rest_framework
 -- pip install djangorestframework
 -- 註冊rest_framework
序列化
 -- Python--json
 -- 第一版 用values以及JsonResponse實現序列化
 -- 第二版 用Django的serialize實現的序列化
  -- 缺點  不能序列化外來鍵關係
 -- 第三版用DRF實現序列化
  -- 第一步宣告序列化器
  -- 第二步 使用我們的序列化器序列化queryset
   -- 把模型物件放入序列化器進行欄位匹配
    匹配上的欄位進行序列化 匹配不上丟棄
  -- 序列化好的資料在ser_obj.data中
 
 -- 外來鍵關係的序列化是巢狀的序列化器物件
  注意many=True

2中序列化方法:

  

from django.shortcuts import render
from django.http import HttpResponse,JsonResponse
from django.views import View
from djangoDome.models import Book,Publisher,Author
from django.core import serializers #django序列化


# 用values 方法獲取
class BookView(View):
def get(self,request):
book_obj=Book.objects.values("id", "title","pub_time", "publisher")
book_list=list(book_obj) [{}]
ret=[]
for book in book_list:
book["publisher"]={
"id": book["publisher"],
"title": Publisher.objects.filter(id=book["publisher"]).first().title,
}
ret.append(book)
return JsonResponse(ret,safe=False,json_dumps_params={"ensure_ascii": False})

# django的序列化
class BookView(View):
def get(self,request):
book_obj=Book.objects.all()
data=serializers.serialize('json',book_obj,ensure_ascii=False)
return HttpResponse(data)

用第三種:
#宣告序列化器
from rest_framework import serializers

class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)

class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32)


class BookSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
pub_time = serializers.DateField()
category=serializers.CharField(source='get_category_display') #此處為多選時用

publisher=PublisherSerializer() #多對一
authors=AuthorSerializer(many=True) #多對多用 many=True
------------------------
from rest_framework.views import APIView #檢視
from djangoDome.models import Book
from rest_framework.response import Response #相等於django的render等
from SerDemo.serializers import BookSerializer

class BookView(APIView):
def get(self,request):
book_obj=Book.objects.all()#獲取所有資料

# 用序列化器進行序列化
ser_obj= BookSerializer(book_obj,many=True)
return Response(ser_obj.data)


Serializers 序列化元件
 

為什麼要用序列化元件

當我們做前後端分離的專案~~我們前後端互動一般都選擇JSON資料格式,JSON是一個輕量級的資料互動格式。

那麼我們給前端資料的時候都要轉成json格式,那就需要對我們從資料庫拿到的資料進行序列化。

接下來我們看下django序列化和rest_framework序列化的對比~~

Django的序列化方法

複製程式碼
class BooksView(View):
    def get(self, request):
        book_list = Book.objects.values("id", "title", "chapter", "pub_time", "publisher")
        book_list = list(book_list)
        # 如果我們需要取外來鍵關聯的欄位資訊 需要迴圈獲取外來鍵 再去資料庫查然後拼接成我們想要的
        ret = []
        for book in book_list:
            pub_dict = {}
            pub_obj = Publish.objects.filter(pk=book["publisher"]).first()
            pub_dict["id"] = pub_obj.pk
            pub_dict["title"] = pub_obj.title
            book["publisher"] = pub_dict
            ret.append(book)
        ret = json.dumps(book_list, ensure_ascii=False, cls=MyJson)
        return HttpResponse(ret)


# json.JSONEncoder.default()
# 解決json不能序列化時間欄位的問題
class MyJson(json.JSONEncoder):
    def default(self, field):
        if isinstance(field, datetime.datetime):
            return field.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(field, datetime.date):
            return field.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, field)
複製程式碼 .values 序列化結果 複製程式碼
from django.core import serializers


# 能夠得到我們要的效果 結構有點複雜
class BooksView(View):
    def get(self, request):
        book_list = Book.objects.all()
        ret = serializers.serialize("json", book_list)
        return HttpResponse(ret)
複製程式碼 django serializers

 DRF序列化的方法

首先,我們要用DRF的序列化,就要遵循人家框架的一些標準,

  -- Django我們CBV繼承類是View,現在DRF我們要用APIView

  -- Django中返回的時候我們用HTTPResponse,JsonResponse,render ,DRF我們用Response

為什麼這麼用~我們之後會詳細講~~我們繼續來看序列化~~

序列化

複製程式碼
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display")
    pub_time = serializers.DateField()
複製程式碼 第一步 宣告序列化類 複製程式碼
from rest_framework.views import APIView
from rest_framework.response import Response

class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        ret = BookSerializer(book_list, many=True)
        return Response(ret.data)
複製程式碼 第二步 序列化物件

外來鍵關係的序列化

複製程式碼
# by gaoxin
from rest_framework import serializers
from .models import Book


class PublisherSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)


class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=32)
    age = serializers.IntegerField()


class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    user = UserSerializer(many=True, read_only=True)
複製程式碼 外來鍵關係的序列化

反序列化

當前端給我們發post的請求的時候~前端給我們傳過來的資料~我們要進行一些校驗然後儲存到資料庫~

這些校驗以及儲存工作,DRF的Serializer也給我們提供了一些方法了~~

首先~我們要寫反序列化用的一些欄位~有些欄位要跟序列化區分開~~

Serializer提供了.is_valid()  和.save()方法~~

複製程式碼
# serializers.py 檔案
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    w_chapter = serializers.IntegerField(write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    user = UserSerializer(many=True, read_only=True)

    users = serializers.ListField(write_only=True)
    publisher_id = serializers.IntegerField(write_only=True)

    def create(self, validated_data):
        book = Book.objects.create(title=validated_data["title"], chapter=validated_data["w_chapter"], pub_time=validated_data["pub_time"],                                  publisher_id=validated_data["publisher_id"])
        book.user.add(*validated_data["users"])
        return book
複製程式碼 反序列化serializer.py 複製程式碼
class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        ret = BookSerializer(book_list, many=True)
        return Response(ret.data)

    def post(self, request):
        # book_obj = request.data
        print(request.data)
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            print(12341253)
            serializer.save()
            return Response(serializer.validated_data)
        else:
            return Response(serializer.errors)
複製程式碼 反序列化views.py

當前端給我們傳送patch請求的時候,前端傳給我們使用者要更新的資料,我們要對資料進行部分驗證~~

複製程式碼
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    w_chapter = serializers.IntegerField(write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    user = UserSerializer(many=True, read_only=True)

    users = serializers.ListField(write_only=True)
    publisher_id = serializers.IntegerField(write_only=True)

    def create(self, validated_data):
        book = Book.objects.create(title=validated_data["title"], chapter=validated_data["w_chapter"], pub_time=validated_data["pub_time"],
                                   publisher_id=validated_data["publisher_id"])
        book.user.add(*validated_data["users"])
        return book

    def update(self, instance, validated_data):
        instance.title = validated_data.get("title", instance.title)
        instance.chapter = validated_data.get("w_chapter", instance.chapter)
        instance.pub_time = validated_data.get("pub_time", instance.pub_time)
        instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
        if validated_data.get("users"):
            instance.user.set(validated_data.get("users"))
        instance.save()
        return instance
複製程式碼 PATCH請求serializers.py 複製程式碼
class BookView(APIView):
     def patch(self, request):
        print(request.data)
        book_id = request.data["id"]
        book_info = request.data["book_info"]
        book_obj = Book.objects.filter(pk=book_id).first()
        serializer = BookSerializer(book_obj, data=book_info, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.validated_data)
        else:
            return Response(serializer.errors)
複製程式碼 PATCH請求views.py

 驗證

如果我們需要對一些欄位進行自定義的驗證~DRF也給我們提供了鉤子方法~~

複製程式碼
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    # 省略了一些欄位 跟上面程式碼裡一樣的
    # 。。。。。
     def validate_title(self, value):
        if "python" not in value.lower():
            raise serializers.ValidationError("標題必須含有Python")
        return value
複製程式碼 單個欄位的驗證 複製程式碼
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    w_chapter = serializers.IntegerField(write_only=True)
    pub_time = serializers.DateField()
    date_added = serializers.DateField(write_only=True)
    # 新增了一個上架時間欄位  
    # 省略一些欄位。。都是在原基礎程式碼上增加的
    # 。。。。。。

    # 對多個欄位進行驗證 要求上架日期不能早於出版日期 上架日期要大
    def validate(self, attrs):
        if attrs["pub_time"] > attrs["date_added"]:
            raise serializers.ValidationError("上架日期不能早於出版日期")
        return attrs
複製程式碼 多個欄位的驗證 複製程式碼
def my_validate(value):
    if "敏感詞彙" in value.lower:
        raise serializers.ValidationError("包含敏感詞彙,請重新提交")
    return value


class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32, validators=[my_validate])
    # 。。。。。。
    
複製程式碼 驗證器 validators

 ModelSerializer

現在我們已經清楚了Serializer的用法,會發現我們所有的序列化跟我們的模型都緊密相關~

那麼,DRF也給我們提供了跟模型緊密相關的序列化器~~ModelSerializer~~

  -- 它會根據模型自動生成一組欄位

  -- 它簡單的預設實現了.update()以及.create()方法

定義一個ModelSerializer序列化器

複製程式碼
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"
        # fields = ["id", "title", "pub_time"]
        # exclude = ["user"]
        # 分別是所有欄位 包含某些欄位 排除某些欄位
複製程式碼 定義ModelSerializer

外來鍵關係的序列化

注意:當序列化類MATE中定義了depth時,這個序列化類中引用欄位(外來鍵)則自動變為只讀

複製程式碼
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"
        # fields = ["id", "title", "pub_time"]
        # exclude = ["user"]
        # 分別是所有欄位 包含某些欄位 排除某些欄位
        depth = 1
# depth 代表找巢狀關係的第幾層
複製程式碼 外來鍵關係序列化

自定義欄位

我們可以宣告一些欄位來覆蓋預設欄位,來進行自定製~

比如我們的選擇欄位,預設顯示的是選擇的key,我們要給使用者展示的是value。

複製程式碼
class BookSerializer(serializers.ModelSerializer):
    chapter = serializers.CharField(source="get_chapter_display", read_only=True)
    
    class Meta:
        model = Book
        fields = "__all__"
        # fields = ["id", "title", "pub_time"]
        # exclude = ["user"]
        # 分別是所有欄位 包含某些欄位 排除某些欄位
        depth = 1
複製程式碼 自定義欄位

Meta中其它關鍵字引數

複製程式碼
class BookSerializer(serializers.ModelSerializer):
    chapter = serializers.CharField(source="get_chapter_display", read_only=True)

    class Meta:
        model = Book
        fields = "__all__"
        # fields = ["id", "title", "pub_time"]
        # exclude = ["user"]
        # 分別是所有欄位 包含某些欄位 排除某些欄位
        depth = 1
        read_only_fields = ["id"]
        extra_kwargs = {"title": {"validators": [my_validate,]}}
複製程式碼 Meta中引數

post以及patch請求

由於depth會讓我們外來鍵變成只讀,所以我們再定義一個序列化的類,其實只要去掉depth就可以了~~

複製程式碼
class BookSerializer(serializers.ModelSerializer):
    chapter = serializers.CharField(source="get_chapter_display", read_only=True)

    class Meta:
        model = Book
        fields = "__all__"
        # fields = ["id", "title", "pub_time"]
        # exclude = ["user"]
        # 分別是所有欄位 包含某些欄位 排除某些欄位
        read_only_fields = ["id"]
        extra_kwargs = {"title": {"validators": [my_validate,]}}
複製程式碼 post/patch請求序列化類

SerializerMethodField

外來鍵關聯的物件有很多欄位我們是用不到的~都傳給前端會有資料冗餘~就需要我們自己去定製序列化外來鍵物件的哪些欄位~~

複製程式碼
class BookSerializer(serializers.ModelSerializer):
    chapter = serializers.CharField(source="get_chapter_display", read_only=True)
    user = serializers.SerializerMethodField()
    publisher = serializers.SerializerMethodField()

    def get_user(self, obj):
        # obj是當前序列化的book物件
        users_query_set = obj.user.all()
        return [{"id": user_obj.pk, "name": user_obj.name} for user_obj in users_query_set]

    def get_publisher(self, obj):
        publisher_obj = obj.publisher
        return {"id": publisher_obj.pk, "title": publisher_obj.title}

    class Meta:
        model = Book
        fields = "__all__"
        # fields = ["id", "title", "pub_time"]
        # exclude = ["user"]
        # 分別是所有欄位 包含某些欄位 排除某些欄位
        read_only_fields = ["id"]
        extra_kwargs = {"title": {"validators": [my_validate,]}}
複製程式碼 SerializerMethodField

用ModelSerializer改進上面Serializer的完整版

複製程式碼
class BookSerializer(serializers.ModelSerializer):
    dis_chapter = serializers.SerializerMethodField(read_only=True)
    users = serializers.SerializerMethodField(read_only=True)
    publishers = serializers.SerializerMethodField(read_only=True)

    def get_users(self, obj):
        # obj是當前序列化的book物件
        users_query_set = obj.user.all()
        return [{"id": user_obj.pk, "name": user_obj.name} for user_obj in users_query_set]

    def get_publishers(self, obj):
        publisher_obj = obj.publisher
        return {"id": publisher_obj.pk, "title": publisher_obj.title}

    def get_dis_chapter(self, obj):
        return obj.get_chapter_display()

    class Meta:
        model = Book
        # fields = "__all__"
        # 欄位是有序的
        fields = ["id", "title","dis_chapter", "pub_time", "publishers", "users","chapter", "user", "publisher"]
        # exclude = ["user"]
        # 分別是所有欄位 包含某些欄位 排除某些欄位
        read_only_fields = ["id", "dis_chapter", "users", "publishers"]
        extra_kwargs = {"title": {"validators": [my_validate,]}, "user": {"write_only": True}, "publisher": {"write_only": True},
                        "chapter": {"write_only": True}}
複製程式碼


為什麼要用序列化元件

當我們做前後端分離的專案~~我們前後端互動一般都選擇JSON資料格式,JSON是一個輕量級的資料互動格式。

那麼我們給前端資料的時候都要轉成json格式,那就需要對我們從資料庫拿到的資料進行序列化。

接下來我們看下django序列化和rest_framework序列化的對比~~

Django的序列化方法

複製程式碼
class BooksView(View):
    def get(self, request):
        book_list = Book.objects.values("id", "title", "chapter", "pub_time", "publisher")
        book_list = list(book_list)
        # 如果我們需要取外來鍵關聯的欄位資訊 需要迴圈獲取外來鍵 再去資料庫查然後拼接成我們想要的
        ret = []
        for book in book_list:
            pub_dict = {}
            pub_obj = Publish.objects.filter(pk=book["publisher"]).first()
            pub_dict["id"] = pub_obj.pk
            pub_dict["title"] = pub_obj.title
            book["publisher"] = pub_dict
            ret.append(book)
        ret = json.dumps(book_list, ensure_ascii=False, cls=MyJson)
        return HttpResponse(ret)


# json.JSONEncoder.default()
# 解決json不能序列化時間欄位的問題
class MyJson(json.JSONEncoder):
    def default(self, field):
        if isinstance(field, datetime.datetime):
            return field.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(field, datetime.date):
            return field.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, field)
複製程式碼 .values 序列化結果 複製程式碼
from django.core import serializers


# 能夠得到我們要的效果 結構有點複雜
class BooksView(View):
    def get(self, request):
        book_list = Book.objects.all()
        ret = serializers.serialize("json", book_list)
        return HttpResponse(ret)
複製程式碼 django serializers

 DRF序列化的方法

首先,我們要用DRF的序列化,就要遵循人家框架的一些標準,

  -- Django我們CBV繼承類是View,現在DRF我們要用APIView

  -- Django中返回的時候我們用HTTPResponse,JsonResponse,render ,DRF我們用Response

為什麼這麼用~我們之後會詳細講~~我們繼續來看序列化~~

序列化

複製程式碼
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display")
    pub_time = serializers.DateField()
複製程式碼 第一步 宣告序列化類 複製程式碼
from rest_framework.views import APIView
from rest_framework.response import Response

class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        ret = BookSerializer(book_list, many=True)
        return Response(ret.data)
複製程式碼 第二步 序列化物件

外來鍵關係的序列化

複製程式碼
# by gaoxin
from rest_framework import serializers
from .models import Book


class PublisherSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)


class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=32)
    age = serializers.IntegerField()


class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    user = UserSerializer(many=True, read_only=True)
複製程式碼 外來鍵關係的序列化

反序列化

當前端給我們發post的請求的時候~前端給我們傳過來的資料~我們要進行一些校驗然後儲存到資料庫~

這些校驗以及儲存工作,DRF的Serializer也給我們提供了一些方法了~~

首先~我們要寫反序列化用的一些欄位~有些欄位要跟序列化區分開~~

Serializer提供了.is_valid()  和.save()方法~~

複製程式碼
# serializers.py 檔案
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    w_chapter = serializers.IntegerField(write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    user = UserSerializer(many=True, read_only=True)

    users = serializers.ListField(write_only=True)
    publisher_id = serializers.IntegerField(write_only=True)

    def create(self, validated_data):
        book = Book.objects.create(title=validated_data["title"], chapter=validated_data["w_chapter"], pub_time=validated_data["pub_time"],                                  publisher_id=validated_data["publisher_id"])
        book.user.add(*validated_data["users"])
        return book
複製程式碼 反序列化serializer.py 複製程式碼
class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        ret = BookSerializer(book_list, many=True)
        return Response(ret.data)

    def post(self, request):
        # book_obj = request.data
        print(request.data)
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            print(12341253)
            serializer.save()
            return Response(serializer.validated_data)
        else:
            return Response(serializer.errors)
複製程式碼 反序列化views.py

當前端給我們傳送patch請求的時候,前端傳給我們使用者要更新的資料,我們要對資料進行部分驗證~~

複製程式碼
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    w_chapter = serializers.IntegerField(write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    user = UserSerializer(many=True, read_only=True)

    users = serializers.ListField(write_only=True)
    publisher_id = serializers.IntegerField(write_only=True)

    def create(self, validated_data):
        book = Book.objects.create(title=validated_data["title"], chapter=validated_data["w_chapter"], pub_time=validated_data["pub_time"],
                                   publisher_id=validated_data["publisher_id"])
        book.user.add(*validated_data["users"])
        return book

    def update(self, instance, validated_data):
        instance.title = validated_data.get("title", instance.title)
        instance.chapter = validated_data.get("w_chapter", instance.chapter)
        instance.pub_time = validated_data.get("pub_time", instance.pub_time)
        instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
        if validated_data.get("users"):
            instance.user.set(validated_data.get("users"))
        instance.save()
        return instance
複製程式碼 PATCH請求serializers.py 複製程式碼
class BookView(APIView):
     def patch(self, request):
        print(request.data)
        book_id = request.data["id"]
        book_info = request.data["book_info"]
        book_obj = Book.objects.filter(pk=book_id).first()
        serializer = BookSerializer(book_obj, data=book_info, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.validated_data)
        else:
            return Response(serializer.errors)
複製程式碼 PATCH請求views.py

 驗證

如果我們需要對一些欄位進行自定義的驗證~DRF也給我們提供了鉤子方法~~

複製程式碼
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    # 省略了一些欄位 跟上面程式碼裡一樣的
    # 。。。。。
     def validate_title(self, value):
        if "python" not in value.lower():
            raise serializers.ValidationError("標題必須含有Python")
        return value
複製程式碼 單個欄位的驗證 複製程式碼
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    w_chapter = serializers.IntegerField(write_only=True)
    pub_time = serializers.DateField()
    date_added = serializers.DateField(write_only=True)
    # 新增了一個上架時間欄位  
    # 省略一些欄位。。都是在原基礎程式碼上增加的
    # 。。。。。。

    # 對多個欄位進行驗證 要求上架日期不能早於出版日期 上架日期要大
    def validate(self, attrs):
        if attrs["pub_time"] > attrs["date_added"]:
            raise serializers.ValidationError("上架日期不能早於出版日期")
        return attrs
複製程式碼 多個欄位的驗證 複製程式碼
def my_validate(value):
    if "敏感詞彙" in value.lower:
        raise serializers.ValidationError("包含敏感詞彙,請重新提交")
    return value


class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32, validators=[my_validate])
    # 。。。。。。
    
複製程式碼 驗證器 validators

 ModelSerializer

現在我們已經清楚了Serializer的用法,會發現我們所有的序列化跟我們的模型都緊密相關~

那麼,DRF也給我們提供了跟模型緊密相關的序列化器~~ModelSerializer~~

  -- 它會根據模型自動生成一組欄位

  -- 它簡單的預設實現了.update()以及.create()方法

定義一個ModelSerializer序列化器

複製程式碼
class BookSeri