昨日回顾
# 0 ser=BookSerialzier(instance=qs,many=True)---->ListSerializer[序列化对象,序列化对象]
ser=BookSerialzier(instance=book)---->BookSerialzier
# 1 定制序列化的字段之source,字段参数
- 指定一个要序列化的对象中得字段
- 指定一个要序列化的对象中得方法,方法返回什么,字段就是什么
- 指定连表操作
# 2 定制序列化的字段之 两种方式(为了关联查询)
-方式一:
-在序列化类中写 SerializerMethodField---》get_字段名(self,obj),返回什么这个字段就是什么
-基于对象的跨表查询
-正向:book.publish
-反向:publish.book_set.all()
-方式二:
-在表模型中写方法,方法返回结果
-在序列化类中,使用ListField,DictField...接收
# 3 反序列化的保存和修改
-保存:book:{name:xx,price:18,publish_id:1,authors:[1]}
-视图函数中:ser=BookSerializer(data=request.data)
-ser.is_valid()---->校验过后的数据---》ser.validated_data
-视图类中:ser.save()
-序列化类中:重写 create方法--->自己写保存
-修改:book:{name:xx,price:18,publish_id:1,authors:[1]}
-视图函数中:ser=BookSerializer(data=request.data,instance=book)
-ser.is_valid()---->校验过后的数据---》ser.validated_data
-视图类中:ser.save()
-序列化类中:重写 update方法--->自己写修改
# 4 反序列化校验的四层
# 5 ModelSerializer 继承了 Serializer
-跟表做了关联
-序列化类中写:
class Meta:
model=Book
fields=['id','自定制字段'] # 分析明白:哪些字段是读写,哪些字段是只读,哪些字段是只写
extra_kwargs={'id':{'required':True,'write_only':True}}
book_name=serializer.CharField(source='name',read_only=True)
-基本上不需要重写create和update了
-局部钩子,全局钩子都一样
# 作业讲解:
# 反序列化,小知识点点
今日内容
0 模块与包的使用
# 模块与包
-模块:一个py文件,被别的py文件导入使用,这个py文件称之为模块,运行的这个py文件称之为脚本文件
-包:一个文件夹下有__init__.py
# 模块与包的导入问题
'''
0 导入模块有相对导入和绝对导入,绝对的路径是从环境变量开始的
1 导入任何模块,如果使用绝对导入,都是从环境变量开始导入起
2 脚本文件执行的路径,会自动加入环境变量
3 相对导入的话,是从当前py文件开始计算的
4 以脚本运行的文件,不能使用相对导入,只能用绝对导入
'''
1 反序列化校验源码分析(了解)
# 序列化类的校验功能
-局部钩子:必须 validate_字段名
-全局钩子: validate
# 入口:
-ser.is_valid 才做的校验---》入口
-BookSerializer---》Serializer——-》BaseSerializer---》is_valid---》继承了Field
-is_valid 方法
def is_valid(self, *, raise_exception=False):
# self中没有_validated_data,只有执行完后,才有
if not hasattr(self, '_validated_data'):
try:
# 核心---》这一句
# 想看它的源代码,按住ctrl+鼠标点击是不对的---》只能找当前类的父类
#但它真正的执行是,从根上开始找
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {}
if self._errors and raise_exception:
raise ValidationError(self.errors)
return not bool(self._errors)
-self.run_validation(self.initial_data),不能按住ctrl+鼠标点点击,要从根上开始找
-Serializer的run_validation
def run_validation(self, data=empty):
# 局部钩子
value = self.to_internal_value(data)
try:
# 全局钩子
value = self.validate(value) # BookSerializer只要写了,优先执行它的
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
-self.to_internal_value(data)---》Serializer类的方法
def to_internal_value(self, data):
for field in fields: #序列化类中写的一个个的字段类的对象列表
# 一个field是name对象,field.field_name字符串 name
# self是谁的对象:序列化类的对象,BookSerializer的对象 validate_name
validate_method = getattr(self, 'validate_' + field.field_name, None)
try:
# 字段自己的校验规则
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
# 局部钩子
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
# 总结:
-ser.is_valid---》走局部钩子的代码---》是通过反射获取BookSerializer中写的局部钩子函数,如果写了,就会执行----》走全局钩子代码---》self.validate(value)--->只要序列化类中写了,优先走自己的
2 断言
# 断言
assert hasattr(self, 'initial_data'), (
'Cannot call `.is_valid()` as no `data=` keyword argument was '
'passed when instantiating the serializer instance.'
)
# 断定某个东西是我认为的,如果不是就抛异常
# 等同于if判断+抛异常
def add(a, b):
return a + b
res = add(8, 9)
# assert res == 16, Exception('不等于16')
if not res==16:
raise Exception('不等于16')
print('随便')
3 drf之请求
# 视图类:APIView
# 序列化组件:Serializer,ModelSerializer
# drf:Request类的对象
# drf:Response
3.1 Request类对象的分析
1).data
request.data 返回解析之后的请求体数据。类似于Django中标准的request.POST和 request.FILES属性,但提供如下特性:
包含了解析之后的文件和非文件数据
包含了对POST、PUT、PATCH请求方式解析后的数据
利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
2).query_params
request.query_params与Django标准的request.GET相同,只是更换了更正确的名称而
3) 其他的属性用起来跟之前一样
3.2 请求,能够接受的编码格式
# urlencoded
# form-data
# json
三种都支持
限制只能接受某种或某几种编码格式
# 限制方式一:在视图类上写---》只是局部视图类有效
# 总共有三个:JSONParser, FormParser, MultiPartParser
class BookView(APIView):
parser_classes = [JSONParser, FormParser]
# 限制方式二:在配置文件中写---》全局有效
# drf的配置,统一写成它
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
# 'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
# 全局配置了只支持json,局部想支持3个
-只需要在局部,视图类中,写3个即可
class BookView(APIView):
parser_classes = [JSONParser, FormParser,MultiPartParser]
# 总结:能够处理的请求方式编码
-优先从视图类中找
-再去项目配置文件找
-再去drf默认的配置中找
4 drf之响应
4.1 响应类的对象Response
# return Response({code:100})
-data:响应体的内容,可以字符串,字典,列表
-status:http响应状态码
-drf把所有响应码都定义成了一个常量
template_name:模板名字,用浏览器访问,看到好看的页面,用postman访问,返回正常数据
-自定制页面
-根本不用
headers:响应头加数据(后面讲跨域问题再讲)
-headers={'name':'lqz'}
content_type:响应编码,一般不用
# 三个重要的:data,status,headers
4.2 响应的格式
# 默认是两种:纯json,浏览器看到的样子
# 限制方式一:在视图类上写---》只是局部视图类有效
# 总共有两个个:JSONRenderer,BrowsableAPIRenderer
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookView(APIView):
renderer_classes = [JSONRenderer]
# 限制方式二:在配置文件中写---》全局有效
# drf的配置,统一写成它
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
# 'rest_framework.renderers.BrowsableAPIRenderer',
],
}
# 全局配置了只支持json,局部想支持2个
-只需要在局部,视图类中,写2个即可
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookView(APIView):
renderer_classes = [JSONRenderer,BrowsableAPIRenderer]
5 视图之两个视图基类
# 视图类:
-APIView:之前用过
-GenericAPIView:GenericAPIView继承了APIView
# GenericAPIView
-类属性:
queryset:要序列化的所有数据
serializer_class:序列化类
lookup_field = 'pk' :查询单条时的key值
-方法:
-get_queryset():获取所有要序列化的数据【后期可以重写】
-get_serializer : 返回序列化类
-get_object :获取单个对象
#总结:以后继承GenericAPIView写接口
1 必须配置类属性
queryset
serializer_class
2 想获取要序列化的所有数据
get_queryset()
3 想使用序列化类:
get_serializer
4 想拿单条
get_object
5.1 使用APIView+序列化类+Response写接口
from rest_framework.views import APIView
from .serializer import BookSerialzier
from rest_framework.response import Response
from .models import Book
# class BookView(APIView):
# def get(self, request):
# qs = Book.objects.all()
# ser = BookSerialzier(qs, many=True)
# return Response({'code': 100, 'msg': '成功', 'results': ser.data})
#
# def post(self, request):
# ser = BookSerialzier(data=request.data)
# if ser.is_valid():
# ser.save()
# return Response({'code': 100, 'msg': '成功'})
# else:
# return Response({'code': 100, 'msg': ser.errors})
#
#
# class BookDetailView(APIView):
# def get(self, request, pk):
# book = Book.objects.all().get(pk=pk)
# ser = BookSerialzier(book)
# return Response({'code': 100, 'msg': '成功', 'results': ser.data})
#
# def put(self, request, pk):
# book = Book.objects.get(pk=pk)
# ser = BookSerialzier(data=request.data, instance=book)
# if ser.is_valid():
# ser.save()
# return Response({'code': 100, 'msg': '更新成功'})
# else:
# return Response({'code': 100, 'msg': ser.errors})
####2 使用GenericAPIView+序列化类+Response写接口
# 咱们写的
# class GenericAPIView(APIView):
# query_set=None
# serialzier_class=None
# def get_queryset(self):
# return self.query_set
# def get_serializer(self):
# return self.serialzier_class
# def get_object(self):
# return self.query_set.filter(pk=pk)
# 人家写的
from rest_framework.generics import GenericAPIView
# class BookView(GenericAPIView):
# queryset = Book.objects.all()
# serializer_class = BookSerialzier
#
# def get(self, request):
# qs = self.get_queryset()
# ser = self.get_serializer(qs, many=True)
# return Response({'code': 100, 'msg': '成功', 'results': ser.data})
#
# def post(self, request):
# ser = self.get_serializer(data=request.data)
# if ser.is_valid():
# ser.save()
# return Response({'code': 100, 'msg': '成功'})
# else:
# return Response({'code': 100, 'msg': ser.errors})
#
#
# class BookDetailView(GenericAPIView):
# queryset = Book.objects.all()
# serializer_class = BookSerialzier
#
# def get(self, request, pk):
# book = self.get_object()
# ser = self.get_serializer(book)
# return Response({'code': 100, 'msg': '成功', 'results': ser.data})
#
# def put(self, request, pk):
# book = self.get_object()
# ser = self.get_serializer(data=request.data, instance=book)
# if ser.is_valid():
# ser.save()
# return Response({'code': 100, 'msg': '更新成功'})
# else:
# return Response({'code': 100, 'msg': ser.errors})
5.2 使用GenericAPIView+序列化类+Response写接口
class BookView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerialzier
def get(self, request):
qs = self.get_queryset()
ser = self.get_serializer(qs, many=True)
return Response({'code': 100, 'msg': '成功', 'results': ser.data})
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '成功'})
else:
return Response({'code': 100, 'msg': ser.errors})
class BookDetailView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerialzier
def get(self, request, pk):
book = self.get_object()
ser = self.get_serializer(book)
return Response({'code': 100, 'msg': '成功', 'results': ser.data})
def put(self, request, pk):
book = self.get_object()
ser = self.get_serializer(data=request.data, instance=book)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '更新成功'})
else:
return Response({'code': 100, 'msg': ser.errors})
作业
# 1 原生django想往响应头加数据,如何加?
res=redirect('home')
res['zhu']="zhu"
# 2 编写一个post接口,只能接受json编码格式,响应json格式,响应头中加入
Access-Control-Allow-Origin = "*"
# 3 基于GenericAPIView编写图书5个接口,带出版社和作者
# 4 封装5个类ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin
#实现这种效果
class PublishView(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset = Publish.objects.all()
serializer_class = PublishSerialzier
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class PublishDetailView(GenericAPIView,DestroyModelMixin,UpdateModelMixin,RetrieveModelMixin):
queryset = Publish.objects.all()
serializer_class = PublishSerialzier
def get(self, request, pk):
return self.retrieve(request, pk)
def put(self, request, pk):
return self.update(request, pk)
def delete(self, request, pk):
return self.destroy(request, pk)
####周末作业#######
# 4 基于DRF的Response,封装一个自己的Response,使它更符合我们规范
{code:100,msg:成功,data:...}
# 5 自己封装出9个视图子类,能方便实现5个接口中某一个或多个
class PublishView(ListAPIView):
queryset = Publish.objects.all()
serializer_class = PublishSerialzier
class PublishDetailView(DestroyAPIView):
queryset = Publish.objects.all()
serializer_class = PublishSerialzier
# 6 封装一个视图类,实现某个表的5个接口,使用方式如下(这个比较难)
视图类只需要这么写,就有5个接口
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 7 研究importlib,如何动态导入模块
标签:ser,get,request,self,APIView,序列化,data,Response
From: https://www.cnblogs.com/zxjwt/p/17417416.html