drf3 Serializers 序列化組件

爲何要用序列化組件前端

作先後端分離的項目,咱們先後端交互通常都選擇JSON數據格式,JSON是一個輕量級的數據交互格式。
給前端數據的時候都要轉成json格式,那就須要對從數據庫拿到的數據進行序列化。
django序列化和rest_framework序列化的對比
將後端數據庫中的信息用json的格式傳給前端

 

數據準備python

DRFDemo/urls.py

from django.contrib import admin
from django.urls import path, include


urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', include("SerDemo.urls")),

]





SerDemo/urls.py

urlpatterns = [
    path('list', BookView.as_view()),
    path('retrieve/<int:id>', BookEditView.as_view()),

]
urls
from django.db import models

# Create your models here.

__all__ = ["Book", "Publisher", "Author"]


class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="圖書名稱")
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = models.IntegerField(choices=CHOICES, verbose_name="圖書的類別")
    pub_time = models.DateField(verbose_name="圖書的出版日期")

    publisher = models.ForeignKey(to="Publisher", on_delete=None)
    author = models.ManyToManyField(to="Author")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name_plural = "01-圖書表"
        db_table = verbose_name_plural


class Publisher(models.Model):
    title = models.CharField(max_length=32, verbose_name="出版社的名稱")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name_plural = "02-出版社表"
        db_table = verbose_name_plural


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="做者的姓名")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = "03-做者表"
        db_table = verbose_name_plural
SerDemo/models.py
for table in models.__all__:
    admin.site.register(getattr(models, table))
SerDemo/admin.py

 

須要本身手動,對取出來的數據進行序列化後返回數據庫

class BookView(View):

        # 初版 用.values JsonResponse實現序列化
        def get(self, request):
            book_list = Book.objects.values("id", "title", "category", "pub_time", "publisher")
            book_list = list(book_list)
            ret = []
            for book in book_list:
                # print(book)
                publisher_id = book["publisher"]
                publisher_obj = Publisher.objects.filter(id=publisher_id).first()

                book["publisher"] = {      # 將 publisher 對應的出版社,序列化
                    "id": publisher_id,
                    "title": publisher_obj.title
                }
                ret.append(book)
            # ret = json.dumps(book_list, ensure_ascii=False)  # json.dumps 不能處理日期格式數據
            # return HttpResponse(ret)

            # 使用JsonResponse 能幫咱們處理
            return JsonResponse(ret, safe=False, json_dumps_params={"ensure_ascii": False})
# 初版 用.values JsonResponse實現序列化

 

 

class BookView(View):
      
    # 第二版 用django serializers實現序列化
    def get(self, request):
        book_list = Book.objects.all()
        ret = serializers.serialize("json", book_list, ensure_ascii=False)
        return HttpResponse(ret)
# 第二版 用django serializers實現序列化

 序列化仍舊處於表層,第二級如下的數據顯示爲數字django

 

DRF序列化

用DRF的序列化,要遵循框架的一些標準,json

  -- Django咱們CBV繼承類是View,如今DRF咱們要用APIView後端

  -- Django中返回的時候咱們用HTTPResponse,JsonResponse,render ,DRF咱們用Responsesession

安裝 pip install djangorestframeworkapp

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'SerDemo',
    'rest_framework',
]
註冊到項目的app裏面

序列化

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES,source="get_category_display")
    pub_time = serializers.DateField()
編寫序列化的類
from rest_framework.views import APIView

from rest_framework.response import Response
from .serializers import BookSerializer  # 導入序列化類
class BookView(APIView):

    def get(self, request):
        book_obj = Book.objects.first()
        ret = BookSerializer(book_obj)
        # book_list = Book.objects.all()  # 拿到全部的對象
        # ret = BookSerializer(book_list, many=True)
        return Response(ret.data)
視圖函數(序列化對象)

  ret = BookSerializer(book_list, many=True)  序列化多個對象時,須要設置many=True框架

image

含外鍵數據的序列化

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)
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display")
    pub_time = serializers.DateField()

    publisher = PublisherSerializer()
    author = AuthorSerializer(many=True)
外鍵關係的序列化

 

image

DRF反序列化

當前端給咱們發post的請求的時候~前端給咱們傳過來的數據~咱們要進行一些校驗而後保存到數據庫
這些校驗以及保存工做,DRF的Serializer也給咱們提供了一些方法了
首先~咱們要寫反序列化用的一些字段~有些字段要跟序列化區分開
Serializer提供了.is_valid()  和.save()方法
將前端傳過來的數據進行反序列化,而後保存到數據庫

read_only=True #序列化
write_only=True #反序列化數據
前端傳過來的數據樣式
{
    "title": "Alex的使用教程",
    "w_category": 1,
    "pub_time": "2018-10-09",
    "publisher_id": 1,
    "author_list": [1, 2]
}

 

接受Post前端傳過來的數據,必須在serialise類定義create方法前後端分離

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)  #不須要校驗
    title = serializers.CharField(max_length=32, validators=[my_validate])
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author = AuthorSerializer(many=True, read_only=True)
    author_list = serializers.ListField(write_only=True) #反序列化字段

    def create(self, validated_data): # 建立數據,接受post 數據
        book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
                                pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])  # 取數據的時候應該爲前端傳過來的字段數據
        book.author.add(*validated_data["author_list"]) #多對多
        return book
反序列化serializer.py

定義 post 方法接受前端傳過來的數據

class BookView(APIView):

    def get(self, request):
        # book_obj = Book.objects.first()
        # ret = BookSerializer(book_obj)
        book_list = Book.objects.all()
        ret = BookSerializer(book_list, many=True)
        return Response(ret.data)

    def post(self, request):
        print(request.data)
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)  #校驗成功,反回
        else:
            return Response(serializer.errors)
反序列化views.py

 

post數據

image

反回的結果

image

DRF的PUT請求部分驗證

單條數據操做

from django.urls import path, include
from .views import BookView, BookEditView

urlpatterns = [
    path('list', BookView.as_view()),
    path('retrieve/<int:id>', BookEditView.as_view()),

]

 

BookEditView

class BookEditView(APIView):

    def get(self, request, id):  # 獲取單條數據
        book_obj = Book.objects.filter(id=id).first()
        ret = BookSerializer(book_obj)
        return Response(ret.data)

    def put(self, request, id):  # 部分修改數據
        book_obj = Book.objects.filter(id=id).first()
        serializer = BookSerializer(book_obj, data=request.data, partial=True) # partial=True # 支持部分驗證
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

    def delete(self, request, id):
        book_obj = Book.objects.filter(id=id).first()
        book_obj.delete()
        return Response("")
單條數據操做

 

查看單條數據,獲取id爲4的數據

image

 

修改數據

前端傳過來的數據

data = {
    "title": "Alex的使用教程2"
}

對修改的數據進行序列化處理 update 方法

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)  #不須要校驗
    title = serializers.CharField(max_length=32, validators=[my_validate])
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author = AuthorSerializer(many=True, read_only=True)
    author_list = serializers.ListField(write_only=True)

    def update(self, instance, validated_data):   # 處理 put 更新數據
        instance.title = validated_data.get("title", instance.title)
        instance.category = validated_data.get("category", instance.category)
        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("author_list"):
            instance.author.set(validated_data["author_list"])
        instance.save()
        return instance
Serializer的update更新數據

 

image

反回的結果

image

 

DRF的驗證

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)  # 不須要校驗
    title = serializers.CharField(max_length=32, validators=[my_validate])
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author = AuthorSerializer(many=True, read_only=True)
    author_list = serializers.ListField(write_only=True)

    def create(self, validated_data):  # 建立數據
        book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
                                   pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
        book.author.add(*validated_data["author_list"])  # 多對多
        return book

    def update(self, instance, validated_data):  # 處理 put 更新數據
        instance.title = validated_data.get("title", instance.title)
        instance.category = validated_data.get("category", instance.category)
        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("author_list"):
            instance.author.set(validated_data["author_list"])
        instance.save()
        return instance
BookSerializer
    def validate_title(self, value):   # 對傳過來的title進行校驗
        if "python" not in value.lower():
            raise serializers.ValidationError("標題必須含有python")
        return value

    def validate(self, attrs):  # 全局校驗
        if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
            return attrs
        else:
            raise serializers.ValidationError("分類以及標題不符合要求")

 

image

image

 

image

image

 

自定義驗證器

當有重疊校驗器時自定義的驗證器權重更高

def my_validate(value):  # 自定義驗證器,權重更高,用在須要校驗數據的地方
    if "敏感信息" in value.lower():
        raise serializers.ValidationError("不能含有敏感信息")
    else:
        return value
使用
title = serializers.CharField(max_length=32, validators=[my_validate])

 all

from rest_framework import serializers
from .models import Book


# 外鍵序列化
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)


#
# # 傳過來的書籍對象數據
# book_obj = {
#     "title": "Alex的使用教程",
#     "w_category": 1,
#     "pub_time": "2018-10-09",
#     "publisher_id": 1,
#     "author_list": [1, 2]
# }
#
# data = {
#     "title": "Alex的使用教程2"
# }


def my_validate(value):  # 自定義驗證器,權重更高,
    if "敏感信息" in value.lower():
        raise serializers.ValidationError("不能含有敏感信息")
    else:
        return value


class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)  # 不須要校驗
    title = serializers.CharField(max_length=32, validators=[my_validate])
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author = AuthorSerializer(many=True, read_only=True)
    author_list = serializers.ListField(write_only=True)
#
    def create(self, validated_data):  # 建立數據
        book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
                                   pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
        book.author.add(*validated_data["author_list"])  # 多對多
        return book
#
    def update(self, instance, validated_data):  # 處理 put 更新數據
        instance.title = validated_data.get("title", instance.title)
        instance.category = validated_data.get("category", instance.category)
        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("author_list"):
            instance.author.set(validated_data["author_list"])
        instance.save()
        return instance

    def validate_title(self, value):  # 對傳過來的title進行校驗
        if "python" not in value.lower():
            raise serializers.ValidationError("標題必須含有python")
        return value

    def validate(self, attrs):
        if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
            return attrs
        else:
            raise serializers.ValidationError("分類以及標題不符合要求")
serializers.Serializer

 

ModelSerializer序列化

如今咱們已經清楚了Serializer的用法,會發現咱們全部的序列化跟咱們的模型都緊密相關~

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

  -- 它會根據模型自動生成一組字段

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

 

 

image

image

 

# 注意:當序列化類MATE中定義了depth時,這個序列化類中引用字段(外鍵)則自動變爲只讀

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"
        # fields = ["id", "title", "pub_time"]
        # exclude = ["user"]
        # 分別是全部字段 包含某些字段 排除某些字段
        depth = 1
# depth 表明找嵌套關係的第幾層
外鍵關係的序列化
# depth = 1 #對第二級別的字段也進行序列化

image

 

class BookSerializer(serializers.ModelSerializer):
    category = serializers.CharField(source="get_category_display")
    class Meta:
        model = Book  # 對應的 model
        # fields = ["id", "title", "pub_time"]
        fields = "__all__"  # 全部字段
        depth = 1  # 外鍵深度爲1

image

 

 

拿到了較多的冗餘字段

經過 SerializerMethodField 只取想要的字段,而後在下面定義各自的獲取方法

自定義字段

class BookSerializer(serializers.ModelSerializer):

    # 只取想要的字段,
    category_display = serializers.SerializerMethodField(read_only=True)
    publisher_info = serializers.SerializerMethodField(read_only=True)
    authors = serializers.SerializerMethodField(read_only=True)

    def get_category_display(self, obj):
        return obj.get_category_display()

    def get_authors(self, obj):
        authors_query_set = obj.author.all()
        return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_query_set]

    def get_publisher_info(self, obj):
        # obj 是咱們序列化的每一個Book對象
        publisher_obj = obj.publisher
        return {"id": publisher_obj.id, "title": publisher_obj.title}

 

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中其它關鍵字參數
因爲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請求 

ModelSerializer反序列化

ModelSerializer 默認已經幫咱們作了反序列化(不用寫 create 方法)接受post 數據

image

image

 

class BookSerializer(serializers.ModelSerializer):

    # 只取想要的字段,
    category_display = serializers.SerializerMethodField(read_only=True)     # 序列化(顯示的時候)的 顯示
    publisher_info = serializers.SerializerMethodField(read_only=True)
    authors = serializers.SerializerMethodField(read_only=True)

    # 定義獲取字段的方法
    def get_category_display(self, obj):
        return obj.get_category_display()


    def get_authors(self, obj):
        authors_query_set = obj.author.all()
        return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_query_set]

    def get_publisher_info(self, obj):
        # obj 是咱們序列化的每一個Book對象
        publisher_obj = obj.publisher
        return {"id": publisher_obj.id, "title": publisher_obj.title}

    # category = serializers.CharField(source="get_category_display")
    class Meta:
        model = Book  # 對應的 model
        # fields = ["id", "title", "pub_time"]
        fields = "__all__"
        # depth = 1

        # 字段的額外參數, "write_only": True 讓下面這字段在反序列化的時候顯示
        extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True},
                        "author": {"write_only": True}}
serializers.ModelSerializer
from rest_framework import serializers
from .models import Book


# 外鍵序列化
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)


#
# # 傳過來的書籍對象數據
# book_obj = {
#     "title": "Alex的使用教程",
#     "w_category": 1,
#     "pub_time": "2018-10-09",
#     "publisher_id": 1,
#     "author_list": [1, 2]
# }
#
# data = {
#     "title": "Alex的使用教程2"
# }


def my_validate(value):  # 自定義驗證器,權重更高,
    if "敏感信息" in value.lower():
        raise serializers.ValidationError("不能含有敏感信息")
    else:
        return value


# class BookSerializer(serializers.Serializer):
#     id = serializers.IntegerField(required=False)  # 不須要校驗
#     title = serializers.CharField(max_length=32, validators=[my_validate])
#     CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
#     category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
#     w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
#     pub_time = serializers.DateField()
#
#     publisher = PublisherSerializer(read_only=True)
#     publisher_id = serializers.IntegerField(write_only=True)
#     author = AuthorSerializer(many=True, read_only=True)
#     author_list = serializers.ListField(write_only=True)
#
#     def create(self, validated_data):  # 建立數據
#         book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
#                                    pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
#         book.author.add(*validated_data["author_list"])  # 多對多
#         return book
#
#     def update(self, instance, validated_data):  # 處理 put 更新數據
#         instance.title = validated_data.get("title", instance.title)
#         instance.category = validated_data.get("category", instance.category)
#         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("author_list"):
#             instance.author.set(validated_data["author_list"])
#         instance.save()
#         return instance
#
#     def validate_title(self, value):  # 對傳過來的title進行校驗
#         if "python" not in value.lower():
#             raise serializers.ValidationError("標題必須含有python")
#         return value
#
#     def validate(self, attrs):
#         if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
#             return attrs
#         else:
#             raise serializers.ValidationError("分類以及標題不符合要求")

# 方法二
class BookSerializer(serializers.ModelSerializer):

    # 只取想要的字段,
    category_display = serializers.SerializerMethodField(read_only=True)     # 序列化(顯示的時候)的 顯示
    publisher_info = serializers.SerializerMethodField(read_only=True)
    authors = serializers.SerializerMethodField(read_only=True)

    # 定義獲取字段的方法
    def get_category_display(self, obj):
        return obj.get_category_display()


    def get_authors(self, obj):
        authors_query_set = obj.author.all()
        return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_query_set]

    def get_publisher_info(self, obj):
        # obj 是咱們序列化的每一個Book對象
        publisher_obj = obj.publisher
        return {"id": publisher_obj.id, "title": publisher_obj.title}

    # category = serializers.CharField(source="get_category_display")
    class Meta:
        model = Book  # 對應的 model
        # fields = ["id", "title", "pub_time"]
        fields = "__all__"
        # depth = 1

        # 字段的額外參數, "write_only": True 反序列化的時候顯示
        extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True},
                        "author": {"write_only": True}}
serializers.py

序列化組件小結

 

相關文章
相關標籤/搜索