2、反序列化操作
反序列化流程——json数据----->字典----->校验---->模型类对象
如果模型类字段有默认值 设置序列化器时 required=False 如果为必传参数 required=True
read_only = True指的是当前字段只作用于序列化操作
write_only = True指的是当前字段只作用于反序列化操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fk3NQoLr-1587053511032)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\1578716208575.png)]
1.反序列化校验流程
1.获取校验的字段数据
book_info = {"id":9,"btitle":"狼图腾","bpub_date":"2020-1-11"}
2.构建序列化器对象
bs = BookInfoSerializer(data=book_info) # data指明要校验的字典数据 data必须写
3.启动校验步骤
bs.is_valid() # 校验成功返回True 失败返回False
4.当且仅当校验成功之后,才会生成有效数据
bs.validated_data # 最终的有效数据
# 生成的数据 OrderedDict([('btitle', '狼图腾'), ('bpub_date', datetime.date(2020, 1, 11))])
类型:字典 会根据字段指明的类型做适当的转换
校验失败查看错误信息
bs.errors # 查看校验失败的信息
# 如果校验失败 不会产生有效数据
2.校验的分类
1.约束条件校验
2.类型校验
3.使用validators约束条件指明的单一字段校验函数——validators=列表或者是元组
# 校验单一字段
def check_btitle(value):
"""
功能:校验btitle中包含django
value为当前字段经过前序校验之后的数据
:return:
"""
if 'django' not in value:
# 如果校验失败 通过抛异常的方式通知调用者(序列化器)校验失败
# 必须抛出drf中的ValidationError异常,异常会被drf自动捕获,返回合适的响应对象
raise serializers.ValidationError('这不是一本关于django的书')
# 1、定义一个序列化器,来序列化BookInfo模型类对象
# Serializer: 是drf中自定义序列化器的基类
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
# read_oly = True表示当前字段只作用于序列化操作,对于反序列化是新增 id会自动增加 因此id作用于序列化
id = serializers.IntegerField(label='ID', read_only=True)
# write_only = True 表示当前字段只能作用于反序列化操作
btitle = serializers.CharField(label='名称',
max_length=20,
# write_only=True,
validators=[check_btitle]
)
bpub_date = serializers.DateField(label='发布日期',
required=True,
)
bread = serializers.IntegerField(label='阅读量', required=False)
bcomment = serializers.IntegerField(label='评论量', required=False)
image = serializers.ImageField(label='图片', required=False)
4.通过自定义方法校验单一字段的校验函数:validate_校验的字段名
# 通过自定义方法来针对单一字段的校验
# validate_<字段名>
# 必须写在对应的序列化器内部
def validate_bpub_date(self, value):
"""
日期要大于2020-1-1
:param value: 经过前序校验的当前字段的数据,类型是date类型
:return: 一定要返回经过本次校验之后产生的"有效数据"
"""
if value <= date(year=2020, month=1, day=1):
# 校验失败
raise serializers.ValidationError("日期必须大于2020-1-1")
return value
5.重写validate函数为最后一步校验,返回值为最终的有效数据
# 必须写在对应的序列化器内部
def validated(self,attrs):
"""
自定义校验逻辑
attrs:经过前序校验的所有字段的数据,类型是字典
返回真正的有效数据
"""
print(type(attrs),attrs)
# 类型是:<class 'collections.OrderedDict'>
# OrderedDict([('btitle', 'django新版'), ('bpub_date', datetime.date(2020,, 10))])
return attrs
序列化器新建数据流程
校验成功之后,新建模型类对象
1.数据校验 产生有效数据(具体流程如下)
1.1 准备数据
book = {"btitle":"django新版","bpub_date":"2020-1-11"}
1.2构建序列化对象
bs = BookInfoSerializer(data=book)
1.3开启校验
bs.is_valid() # 返回True或者是False
bs.validated_data # 查看有效数据
# OrderedDict([('btitle', 'django新版'), ('bpub_date', datetime.date(2020, 1, 10))])
# 校验成功之后,新建
bs.save()
2.校验成功之后,新建
调用序列化器的save方法实现新建 save方法内部重写了create方法 自动传入数据
前提:重写create方法 补充新建逻辑代码
# 创建模型类对象
def create(self, validated_data):
"""
序列化器 用来新建模型类对象
:param validated_data: 校验之后的有效数据
:return: 返回新建的模型类对象
"""
instance = BookInfo(**validated_data)
instance.save()
return instance
序列化器更新数据流程
校验成功之后 更新数据模型类对象
第一步:数据校验,产生有效数据(具体流程如下)
1.准备需要更新的数据和需要被更新的目标模型类对象
2.构建序列化对象(data里面传入更新数据,instance传入被更新的模型类对象)
3.启用校验
# 1.准备需要更新的数据
book_info = {"btitle":"django新版基础","bpub_date":"2020-1-5"}
# 需要操作的目标模型类对象
book = BookInfo.objects.get(pk=8)
# 2.构建序列化对象
bs = BookInfoSerializer(instance=book,data=book_info)
# 3.启用校验
bs.is_valid()
# 4.保存更新的数据
bs.save()
第二步:校验成功,更新数据(具体流程)
1.重写序列化器里面的update方法
2.调用序列化对象的save方法实现更新,save内部会调用重写update方法 自动传入被更新的对象 和有效数据
#更新模型类对象
def update(self, instance, validated_data):
"""
更新模型类对象
:param instance: 被更新的模型类对象
:param validated_data: 更新的有效数据
:return: 返回更新的模型类对象
"""
new_btitle = validated_data['btitle']
new_bpub_date = validated_data['bpub_date']
instance.btitle = new_btitle
instance.bpub_date = new_bpub_date
instance.save()
return instance
模型类序列化器
作用——1.自动映射模型类字段 2.不需要重写create、update方法
自定义序列化器——会把对应模型类的所有字段全部映射
from rest_framework import serializers
from .models import BookInfo,HeroInfo
class BookInfoModelSerializer(serializers.ModelSerializer):
# 声明序列化或反序列化操作字段有哪些,针对的是哪个模型类
class Meta:
model=BookInfo # 通过Meta的model类属性,指明当前序列化器操作的模型类为BookInfo
fileds='__all__' # 把BookInfo模型类的所有字段 自动映射到序列化器
#fileds=['btitle','bpub_date'] # 只映射btitle和bpub_date这两个字段
class HeroInfoModelSerializer(serializers.ModelSerializer):
class Meta:
model=HeroInfo
fileds='__all__'
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rCgJYp4a-1587053511035)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\1578900985830.png)]
映射全部的字段会出现部分字段的值不合理,修改方法有两种:
第一种方法:在当前序列化器里面 显示定义的字段和类型 修改里面的数值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BMrIkLUk-1587053511038)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\1578745553111.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iTBiUvKq-1587053511041)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\1578745567008.png)]
第二种方法:在class Meta 类里面有一个extra_kwargs字典 修改自动映射的约束条件
# 修改自动映射的约束条件
extra_kwargs={
'bread':{'min_value':0}
}
用模型类序列化器也可以实现序列化和反序列化操作
# 序列化操作
# 单个对象
book = BookInfo.objects.all()[3]
bs = BooksInfoModelSerializer(instance=book)
bs.data
# 多个对象
book = BookInfo.objects.all()
bs = BooksInfoModelSerializer(book,many=True)
bs.data
# 反序列化操作
# 创建单一对象
book_info = {"btitle":"django新版","bpub_date":"2020-1-1"}
bs = BooksInfoModelSerializer(data=book_info)
bs.is_valid()
bs.save()
# 更新数据
book_info = {"btitle":"django新版","bpub_date":"2020-1-6"}
book = BookInfo.objects.get(pk=8)
bs = BooksInfoModelSerializer(book,data=book_info)
bs.is_valid()
bs.save()
APIView视图函数
1.drf响应对象——Reseponse
1.模块——from rest_framework.response import Response
2.状态码模块——from rest_framework.status import HTTP_200_OK
3.Reseponse(data={},status=状态码,headers={})
2.drf请求对象——request
request——drf对django的请求对象再次封装得到的请求对象
drf中提取查询字符串参数
request.query_params # 得到的多值字典(一个key对应多个值)
request.query_params.get('key') # 得到最后一个值
request.query_params.getlist('key') #得到所有key所对应的值
drf中获取请求体参数(只能是json,form表单数据)
request.data # 直接得到的是字典
#如果是自定义的请求体数据 则需要用request.body得到字节数据 转化 执行后续操作
3.APIView获取多个数据
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.status import HTTP_200_OK,HTTP_201_CREATED,HTTP_400_BAD_REQUEST
from .serializer import *
from test_app.models import BookInfo,HeroInfo
class BooksInfoAPIView(APIView):
def get(self,request):
# 1.获取查询集
book = BookInfo.objects.all()
# 2.创建序列化对象
serializer = BooksInfoModelSerializer(instance=book,many=True)
# 3.序列化响应
return Response(data=serializer.data,status=HTTP_200_OK)
3.APIView创建单一对象
def post(self,request):
# 1.获取请求体数据
book = request.data
# 2.创建序列化对象
serializer = BooksInfoModelSerializer(data=book)
# 3.校验
#if not serializer.is_valid():
#return Response(data=serializer.errors,status=HTTP_400_BAD_REQUEST)
# raise_exception=True:校验过程中失败了,不再返回True或者是False来提示
# 而是直接把异常抛给视图函数 视图函数自动捕获异常并自动构建响应对象返回
serializer.is_valid(raise_exception=True)
# 4.新建
serializer.save()
# 5.返回序列化数据
return Response(data=serializer.data)
# 这里可以对校验进行简写 需要用到raise_exception
4.APIView获取单一对象
class BookInfoAPIView(APIView):
# 获取单个对象
def get(self,request,pk):
# 获取数据
book = BookInfo.objects.get(pk=pk)
# 构建序列化器对象
serializer = BooksInfoModelSerializer(book)
# 序列化返回
return Response(data=serializer.data)
5.更新数据——全部更新PUT和部分更新PATCH
# 更新数据 分为全部更新PUT和部分更新PATH
# 全部更新
def put(self,request,pk,**kwargs):
partial_result = kwargs.get('partial',False)
# 获取目标对象和更新数据
book = BookInfo.objects.get(pk=pk)
book_info = request.data
# 创建序列化器对象
serializer = BooksInfoModelSerializer(instance=book,data=book_info,partial=partial_result)
# 校验(必传参数必须校验)
serializer.is_valid(raise_exception=True)
# 更新数据
serializer.save()
# 返回更新的序列化数据
return Response(data=serializer.data,status=HTTP_201_CREATED)
# 部分更新
def patch(self,request,pk):
return self.put(request,pk,partial=True)
# 因为部分更新和全部更新的代码逻辑相同 因此可以简化为调用put函数 但是需要注意部分更新需要传入partial=True 而在put函数里面需要传入**kwargs参数 当为部分更新kwargs.get('partial',False)等于True 为全部更新时False
6.删除数据
def delete(self,request,pk):
# 删除数据
book = BookInfo.objects.get(pk=pk)
book.delete()
return Response(data={},status=HTTP_204_NO_CONTENT)
GenericAPIView
重要的函数
def get_queryset(self): # 获取序列化的目标数据查询集 多个对象
def get_object(self) # 获取目标数据 单一对象
def get_serializer(self) # 创建序列化对象
def get_serializer__class(self) # 获取序列化器类
获取查询集多个模型类对象——self.get_queryset()
实例方法——self.get_queryset()获取多个查询集 依赖类属性queryset 默认返回的就是类属性queryset指明 的查询集
类属性——queryset:指明当前的视图处理的默认的数据集
实例方法——self.get_serializer_class():获得处理查询集所使用的序列化器类,依赖类属性self.get_serializer
类属性——serializer_class:指明当前视图处理查询集所默认使用的序列化器
实例方法——self.get_serializer():构建一个序列化器对象 依赖queryset,serializer_class
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
from rest_framework.status import HTTP_200_OK,HTTP_201_CREATED,HTTP_400_BAD_REQUEST,HTTP_204_NO_CONTENT
from .serializer import *
from test_app.models import BookInfo,HeroInfo
class BooksInfoAPIView(GenericAPIView):
# 通过类属性queryset来声明设置当前视图默认处理的查询集
queryset = BookInfo.objects.all()
# 通过类属性serializer_class 设置当前视图默认处理查询集所用的序列化器
serializer_class = BooksInfoModelSerializer # 千万不要加()
# 获取多个数据
def get(self):
# 获取查询集
book_info = self.get_queryset() # 这是一个泛指查询集 因此需要用queryset声明处理的查询集是哪一个
# 创建序列化器对象
# get_serializer也是一个泛指对象 因此需要用serializer_class声明是哪一个序列化对象
serializer = self.get_serializer(instance=book_info,many=True)
# 返回序列化数据
return Response(data=serializer.data)
创建单个对象
# 创建单一数据
def post(self,request):
# 获取前端数据
# 创建序列化对象
serializer = self.get_serializer(data=request.data)
# 校验
serializer.is_valid(raise_exception=True)
# 保存数据
serializer.save()
# 返回序列化数据
return Response(serializer.data)
获取单个对象
class BookInfoAPIView(GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BooksInfoModelSerializer
# lookup_field = 'pk' # 告诉get_object函数,按照pk字段去过滤
# lookup_url_kwarg = 'pk' # 过滤字段的值在哪个命名分组参数中提取
def get(self,request,pk):
# 获取单一数据数据
book_info = self.get_object() # 这里需要声明按照什么去过滤和所需要的值
# 创建序列化对象
serializer=self.get_serializer(instance=book_info)
# 序列化数据返回
return Response(data=serializer.data)
# 这里需要注意 drf默认是按照pk进行过滤
更新数据——全部更新和部分更新
# 全部更新
def put(self,request,pk,**kwargs):
partial_result = kwargs.get('partial',False)
book = self.get_object()
serializer = self.get_serializer(instance=book,data=request.data,partial=partial_result)
serializer.is_valid(raise_exception = True)
serializer.save()
return Response(data=serializer.data,status=HTTP_201_CREATED)
# 部分更新
def patch(self,request,pk):
return self.put(request,pk,partical=True)
删除数据
# 删除
def delete(self,request,pk):
book_info = self.get_object()
book_info.delete()
return Response(data={},status=HTTP_204_NO_CONTENT)
al’,False)
book = self.get_object()
serializer = self.get_serializer(instance=book,data=request.data,partial=partial_result)
serializer.is_valid(raise_exception = True)
serializer.save()
return Response(data=serializer.data,status=HTTP_201_CREATED)
部分更新
def patch(self,request,pk):
return self.put(request,pk,partical=True)
#### 删除数据
```python
# 删除
def delete(self,request,pk):
book_info = self.get_object()
book_info.delete()
return Response(data={},status=HTTP_204_NO_CONTENT)