本系列文章中的上一篇文章:序列化和反序列化(一)
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.titlet["price"] = obj.price# 除非自定义了名字:date = serializers.DateField(source="pub_date")# t["pub_date"] = obj.pub_datet["date"] = obj.datereturn 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_book2、再找 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@propertydef data(self):# 通过以下的源码可知 ret = self.instance 序列化后的结果ret = super().datareturn ReturnDict(ret, serializer=self)3、BaseSerializer 的 data 源码@propertydef 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_listself._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()