rest_framework(4)序列化和反序列化(二)

本系列文章中的上一篇文章:序列化和反序列化(一)

urls.py 代码

from django.urls import re_path
from sers.views import BookDetailView
urlpatterns = [
    re_path(r"sers/book/(\d+)", BookDetailView.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="出版日期")

views.py 代码

导入的包

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

BookSerializer 类

# 定义序列化器
# 一个序列化类是针对某个模型(数据库表)进行设计的
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(**validated_data)

        return new_book

    # 重写父类中的 update 方法,实现更新数据逻辑
    # update 方法需要返回值,因为在源码中 save 方法需要接收 create 方法的返回值
    def update(self, instance, validated_data):
        Book.objects.filter(pk=instance.pk).update(**validated_data)
        update_book = Book.objects.get(pk=instance.pk)

        return update_book

BookDetailView 类

class BookDetailView(APIView):
    # 查找单个书籍对象
    def get(self, request, id):
        book = Book.objects.get(pk=id)
        # 构建序列化器对象
        # 进行序列化处理,返回给前端 JSON 格式数据
        # 默认 many=False,表示对一个对象序列化,而不是对多个对象
        # 得到的 JSON 格式就是一个 {} 的对象形式,而不是一个列表 [{}, {}, ...]
        # 这就是 many 参数的作用
        serializer = BookSerializer(instance=book, many=False)

        """
        serializer.data 时发生以下动作:
            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

            return t
        """
        return Response(serializer.date)

    # 更新部分书籍信息
    def put(self, request, id):
        # 获取提交的更新后的数据
        print(request.data)
        # 获取更新前的对象
        book = Book.objects.get(pk=id)

        # 构建序列化器对象
        # 传入 instance 和 data 两个关键字参数
        # 之所以两个都需要,是因为需要在对象原基础上进行更新,即只更新改变的部分
        # 需要传 instance 是因为在调用 save 方法的时候需要判断是添加还是更新,具体参照源码
        serializer = BookSerializer(instance=book, data=request.data)

        # 对提交的更新后的数据进行校验
        if serializer.is_valid():
            # # 数据合法,进行更新
            # Book.objects.filter(pk=id).updata(**serializer.validated_data)
            # # 获取更新之后的书籍信息
            # update_book = Book.objects.get(pk=id)
            # serializer.instance = update_book

            # 把更新的逻辑抽取出来
            # 提取出来的逻辑都在 update 方法中,详细参见 save 源码,如下
            """
            serializer.save() 的源码
            1、先看序列化器 BookSerializer ,类中没有 save() 方法,
                class BookSerializer(serializers.Serializer):
                    # ...

                    # 重写父类中的 create 方法,实现更新数据逻辑
                    def create(self, validated_data):
                        # ...
                    
                    # 重写父类中的 update 方法,实现更新数据逻辑
                    # update 方法需要返回值,因为在源码中 save 方法需要接收 create 方法的返回值
                    def update(self, instance, validated_data):
                        Book.objects.filter(pk=instance.pk).update(**validated_data)
                        update_book = Book.objects.get(pk=instance.pk)
                        
                        return update_book

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

                    def save(self, **kwargs):
                        # ...
                        # 此时 self 指的是 BookSerializer 的实例对象 serializer
                        # instance 表示的是要序列化的数据
                        # instance 不为空,所以走的是 if 中的代码
                        # 更正一下上一篇文章中关于 save 方法源码的说法
                        # 当序列化器实例对象中有 instance 属性时,即在构建序列化器对象时传入 instance 参数
                        # 就会走 if 中的代码,那么当调用 save 方法时,就是更新数据
                        # 而如果 instance 为空,即没有传递,则走的是 else 中的代码
                        # 此时调用 save 方法就是向数据库插入一条新的数据
                        # create 和 update 方法都需要在子类中重写
                        # 以根据实际的添加和更新逻辑进行操作
                        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.'
                            )
                        
                        # 返回的 instance 用于序列化的时候使用,具体见 serializer.data 的源码
                        return self.instance
            """
            serializer.save()

            """
            serializer.date 的源码解析:
            data 实际上是一个方法,因为该方法上加了 @property,所以可以不加小括号进行调用
            还是按照继承的类对 data 进行查找
            1、先查找 BookSerializer 类,没有
            2、查找 BookSerializer 的父类 serializers.Serializer,找到了
                其中 ret = super().data 调用的是 Serializer 的父类 BaseSerializer 中的 data
                @property
                def data(self):
                    # 通过以下的源码可知 ret = self.instance 序列化后的结果
                    ret = super().data
                    return ReturnDict(ret, serializer=self)
            3、BaseSerializer 的 data 源码
                    @property
                    def data(self):
                        # ...
                        
                        # self 指的是 serializer 
                        # 如果 self 没有 _data 属性,即没有进行序列化
                        if not hasattr(self, '_data'):
                            # 如果 self 有 instance 属性
                            # 并且 self._errors 为 None,即数据都合法,没有错误信息
                            if self.instance is not None and not getattr(self, '_errors', None):
                                # 使用 to_representation 方法对 instance 进行序列化处理
                                # 并将处理结果,即序列化后的数据赋值给 _data 
                                # to_representation 的处理逻辑就是上一篇文章提到的 temp = []; for ... in book_list
                                self._data = self.to_representation(self.instance)
                            elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
                                self._data = self.to_representation(self.validated_data)
                            else:
                                self._data = self.get_initial()
                        
                        # 返回序列化的结果
                        return self._data
            """
            return Response(serializer.date)
        else:
            return Response(serializer.errors)

    def delete(self, request, id):
        Book.objects.get(pk=id).delete()

        return Response()

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