rest_framework(3)序列化和反序列化(一)

本系列文章中的上一篇文章:rest_framework.views.APIView 源码解析

urls.py 文件

from django.urls import path
from sers.views import BookView
urlpatterns = [
    path('sers/book/', BookView.as_view()),
}

models.py 文件

from django.db import models


# Create your models here.
class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书籍名称")
    price = models.IntegerField(verbose_name="价格")
    pub_date = models.DateField(verbose_name="出版日期")

view.py 文件

导入的包

from rest_framework.views import APIView
from rest_framework import serializers
from rest_framework.response import Response
from sers.models import Book

序列化器定义

# 2、定义序列化器
# 一个序列化类是针对某个模型(数据库表)进行设计的
class BookSerializer(serializers.Serializer):
    # 这些字段对应着数据库表的字段和类型
    # CharField、IntegerField、DateField 在反序列化的时候校验数据用的
    # 比如 title 要求是字符串,且长度要求不超过 32 位
    title = serializers.CharField(max_length=32)
    price = serializers.IntegerField()
    # pub_date = serializers.DateField()
    # 如果想序列化后的键的名字自定义
    # 则要指定 source="pub_date" 参数,对应数据库里的字段名
    date = serializers.DateField(source="pub_date")

    # 重写父类中的 create 方法,实现自己的数据保存逻辑
    # create 方法需要返回值,因为在源码中 save 方法需要接收 create 方法的返回值
    def create(self, validated_data):
        new_book = Book.objects.create(**self.validated_data)
        return new_book

BookView 类

get 方法中是序列化的使用,post 方法中是反序列化的使用

class BookView(APIView):
    # 假设有一个 get 请求,查询所有书籍信息
    def get(self, request):
        # 1、获取所有的书籍对象,返回一个 QuerySet 集合
        book_list = Book.objects.all()

        # 3、构建序列化器对象
        # instance=book_list 表示将 book_list 进行序列化
        # many=True 因为要序列化的是一个集合,所以有多个序列化对象, 所以 many=True
        # data=book_list 则表示将 book_list 进行反序列化
        _serializers = BookSerializer(instance=book_list, many=True)

        # 将序列化的结果返回给客户端
        # serializers.data 存放着序列化的结果
        # HttpResponse 将序列化后的结果按照自己的处理逻辑进行解析,然后发回给客户端
        # 但是前端拿到的结果还是有一些不便于阅读
        # return HttpResponse(_serializers.data)

        """
        _serializers.data 时发生以下动作:
            temp = []
            for obj in book_list:
                t = {}
                # BookSerializer 类中有几个字段,字典 t 中就会有几个键值对
                # BookSerializer 类中的字段名要和数据库表字段一样
                # 否则 obj.title 获取值的时候就会出错
                t["title"] = obj.title
                t["price"] = obj.price
                # 除非自定义了名字:date = serializers.DateField(source="pub_date")
                # t["pub_date"] = obj.pub_date
                t["date"] = obj.date
                
                temp.append(t)
            return temp
        """

        # 而利用 rest_framework.response 中的 Response 对序列化的结果进行处理
        # 将会得到一个真正的 Content-Type 为 json 的 json 格式的数据
        return Response(_serializers.data)

    # 假设有一个 post 请求,添加一个书籍
    def post(self, request):
        # 获取前端传过来的要添加的书籍信息
        # 因为继承了 APIView ,request 在 dispatch 中被重新构建了
        # 所以获取 post 请求的数据通过 request.date 得到
        # 得到的数据格式为 json 格式
        # book = request.date

        # 构建序列化器对象
        serializer = BookSerializer(data=request.date)
        # 校验数据
        """
        is_valid() 方法的执行过程:
            遍历所有的字段,看是否满足序列化器中定义的要求
            (如 title 是否是字符串,长度是否超过32位)
            通过校验的字段和其值放在字典 serializer.validated_date 中
            没有通过的字段放在字典 serializer.errors 中,其中键为字段名,值为错误原因
            如果所有字段都通过,is_valid() 方法返回 True,否则返回 False
        """
        if serializer.is_valid():
            # 校验通过,将数据添加到数据库
            # new_book = Book.objects.create(**serializer.validated_data)
            # 一般如果数据库表关系复杂一点的话,那么保存数据到数据库的操作应该抽取出来
            # 应该调用 序列化器实例对象的 save() 方法

            """
            serializer.save() 的源码
            先看序列化器 BookSerializer ,类中没有 save() 方法,
                class BookSerializer(serializers.Serializer):
                    # ...

                    # 重写父类中的 create 方法,实现自己的数据保存逻辑
                    # create 方法需要返回值,因为在源码中 save 方法需要接收 create 方法的返回值
                    def create(self, validated_data):
                        new_book = Book.objects.create(**self.validated_data)
                        return new_book

            再找 BookSerializer 的父类 Serializer,也没有 save() 方法
                class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
                    # ...
            再找 Serializer 的父类 BaseSerializer,找到了 save() 方法
                class BaseSerializer(Field):
                    # create() 方法中什么都没做,而是直接抛出了异常,这样做的目的就是为了让子类重写该方法
                    def create(self, validated_data):
                        raise NotImplementedError('`create()` must be implemented.')

                    def save(self, **kwargs):
                        # ...
                        # 此时 self 指的是 BookSerializer 的实例对象 serializer
                        # instance 表示的是要序列化的数据,因为在 post 方法中进行的是反序列化
                        # 所以传的是 data 关键字参数,没有传 instance
                        # 所以走的是 else 中的代码
                        # 也就是说如果要进行序列化,传 instance 参数,调用 save 方法时走的是 if 中的代码
                        # 如果进行的是反序列化,传的是 data 参数,调用 save 方法走的就是 else 中的代码
                        if self.instance is not None:
                            self.instance = self.update(self.instance, validated_data)
                            assert self.instance is not None, (
                                '`update()` did not return an object instance.'
                            )
                        else:
                            # self.create() 方法的查找:通过一层层的查找最后也是在 BaseSerializer 类中找到了
                            self.instance = self.create(validated_data)
                            assert self.instance is not None, (
                                '`create()` did not return an object instance.'
                            )

                        return self.instance
            """
            serializer.save()

            # 向前端返回这个书籍
            # 数据已经通过校验,直接将传过来的数据序列化之后返回
            return Response(serializer.data)
        else:
            # 校验失败,返回错误信息
            Response(serializer.errors)

你可能感兴趣的:(restful,后端,python,django)