drf5

今日内容概要

  • 反序列化类校验部分源码分析
  • 断言
  • drf之请求和响应
  • 视图组件介绍及两个视图基类
  • 基于GenericAPIView+5个视图扩展类

今日内容详细

反序列化类校验部分源码分析

# 反序列化校验,什么时候,开始执行校验
	视图类中的 ser.is_valid(),就会执行校验,校验通过返回True,不通过返回False
    
    
# 入口:ser.is_valid() 是序列化类的对象,假设序列化类是BookSerializer---》is_valid---》找不到,找到父类BaseSerializer中有 :
   def is_valid(self, *, raise_exception=False):
    
        if not hasattr(self, '_validated_data'):
            try:
                # self序列化类的对象,属性中没有_validated_data,一定会走这句【核心】
                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._validated_data = self.run_validation(self.initial_data) 核心--》self是序列化类的对象
    从Serializer类中找到了run_validation,而不是Field中的run_validation
    
    
    def run_validation(self, data=empty):
        # 字段自己的,validates方法
        (is_empty_value, data) = self.validate_empty_values(data)
        if is_empty_value:
            return data
        # 局部钩子
        value = self.to_internal_value(data)
        try:
            
            self.run_validators(value)
            # 全局钩子
            value = self.validate(value)
 
        except (ValidationError, DjangoValidationError) as exc:
            raise ValidationError(detail=as_serializer_error(exc))

        return value
    
# 局部钩子  self.to_internal_value(data)
     def to_internal_value(self, data):
        ret = OrderedDict()
        errors = OrderedDict()
        fields = self._writable_fields
        # fields写在序列化类中一个个字段类的对象
        for field in fields:
            # self BookSerializer的对象,反射validate_name
            validate_method = getattr(self, 'validate_' + field.field_name, None)
            try:
                # 在执行BookSerializer类中的validate_name方法,传入了要校验的数据
               validated_value = validate_method(validated_value)
            except ValidationError as exc:
                errors[field.field_name] = exc.detail
          
            else:
                set_value(ret, field.source_attrs, validated_value)

        if errors:
            raise ValidationError(errors)

        return ret

断言

关键字assert表示 主要作用就是断定你是不是xx 如果不是就抛出异常

不使用断言

name = 'lzj'
if name == 'lzj':
    print('对了')
else:
    print('错了')
    raise Exception('名字不为lzj ')

使用断言

assert name='lzj'		# 一行搞定

drf之请求与响应

请求

request能够解析前端传入的编码格式 我们可以通过一些方式只解析指定的编码格式

总共有三个编码
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser

JSONParser				json格式
FormParser				urlencoded格式
MultiPartParser			form-data格式

方式一: 在继承自APIView及其子类的视图类中配置(局部配置)
class 视图类名(APIView):
    parser_classes = [编码1,...]

方式二: 在配置文件中配置(全局配置)
	drf自身也有默认的配置
	也可以在django的settings中添加配置
	REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            'rest_formework.parsers.MultiPartParser',
        ],
    }

查找顺序
	视图类自身---》django配置---》drf默认配置

所以当全局只配了1个编码 某个视图类需要3个编码时 可以在自身类中添加配置即可 谁近谁优先

响应

由于drf是django的一个app 所以需要提前在去配置中注册

使用浏览器和postman访问同一个接口的时候 drf响应的格式是不一样的 drf做了判断 如果是浏览器就返回好看一些的 postman只返回json数据

我们也可以自定义响应格式

from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer

方式一:在视图类中写(局部配置)
	class 视图类名(APIView):
        renderer_classes=[响应格式1,...]

方式二:在项目配置文件中写(全局配置)
	REST_FRAMEWORK = {
      'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ],
}

使用顺序和请求的一致
	优先使用视图类中的配置 其次使用项目配置文件中的配置 最后使用内置的

Response源码的属性与方法

视图类的方法返回时 走的是Response的__init__
def __init__(self, 
    data=None,     # 返回的数据 可以是字典 列表或字符串 序列化后返回给前端
    status=None,	# http响应的状态码 默认是200 可以改
    template_name=None, 	# 修改响应模板的样子 可以自己定制
    headers=None,	# 响应头 
    exception=False,	# 是否异常了
    content_type=None) # 响应编码格式 一般不动

视图组件及两个视图基类

# drf 视图,视图类,学过APIView,drf的基类,drf提供的最顶层的类

# APIView跟之前的View区别
    传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
    视图方法可以返回REST framework的Response对象-
    任何APIException异常都会被捕获到,并且处理成合适的响应信息;
    在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制
    
    
# 两个视图基类
	APIVIew
    类属性:
        renderer_classes 			响应格式
        parser_classes 				能够解析的请求格式
        authentication_classes		认证类
        throttle_classes			频率类
        permission_classes			权限类

通过继承,少些代码-----》GenericAPIView---》继承了APIView,有很多新的属性和方法
5个接口的效果一样,但是代码 可用性变高了

	GenericAPIView
    属性
        queryset				要序列化或反序列化的表模型数据
        serializer_class		使用的序列化类
        lookup_field			查询单条的路由分组分出来的字段名
        filter_backends			过滤类的配置(了解)
        pagination_class		分页类的配置(了解)

    方法
        get_queryset			获取要序列化的对象
        get_object				获取单个对象
        get_serializer			获取序列化类 使用它
        get_serializer_class 	获取序列化类 一般重写 不调用
        filter_queryset 		过滤有关系

基于GenericAPIView+5个视图扩展类编写接口

from rest_framework.generics import GenericAPIView

class BookView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        # objs = self.queryset #这里可以拿到,但是不要这么用,GenericAPIView提供了一个方法,
        objs = self.get_queryset()  # 好处,可以重写该方法,后期可扩展性高
        # 取序列化类,不要使用self.serializer_class,而要使用方法
        ser = self.get_serializer(instance=objs, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})


class BookDetailView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    
    def get(self, request, pk):
        obj = self.get_object()  # 获取单条
        ser = self.get_serializer(instance=obj)
        return Response(ser.data)

    def put(self, request, pk):
        obj = self.get_object()
        ser = self.get_serializer(instance=obj, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})
        
    def delete(self, request, pk):
        self.get_object().delete()
        return Response({'code': 100, 'msg': '删除成功'})



 5个视图扩展类 没有继承APIView及其子类 不能单独使用 必须配合GenericAPIView一起用才行
'''
CreateModelMixin: 新增       create方法,代码就是post的代码
DestroyModelMixin:删除     destroy方法
RetrieveModelMixin:查单条   retrieve方法
ListModelMixin:查所有      list 方法
UpdateModelMixin:更新      updata方法
'''

from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, ListModelMixin

基于GenericAPIView+5个视图扩展类写接口

class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    
    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)

class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
posted @ 2023-02-03 21:16  LZJJJ  阅读(44)  评论(0)    收藏  举报