本系列文章中的上一篇文章:序列化和反序列化(一)
from django.urls import re_path
from sers.views import BookDetailView
urlpatterns = [
re_path(r"sers/book/(\d+)", BookDetailView.as_view()),
}
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="出版日期")
from rest_framework.views import APIView from rest_framework import serializers from rest_framework.response import Response from sers.models import Book
# 定义序列化器
# 一个序列化类是针对某个模型(数据库表)进行设计的
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
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()