zoukankan      html  css  js  c++  java
  • 03-四大基本模块

    DRF框架介绍

    安装

    pip install djangorestframework

    DRF框架规范的封装风格

    # 视图: from rest_framework.views import APIView
    # 响应: from rest_framework.response import Responses
    # 请求: from rest_framework.request import Request
    # 序列化: from rest_framework.serializers import Serializer
    # 配置: from rest_framework.settings import APISettings
    # 过滤器: from rest_framework.filters import SearchFilter
    # 分页: from rest_framework.pagination import PageNumberPagination
    # 认证: from rest_framework.authentication import TokenAuthentication
    # 认证: from rest_framework.permissions import IsAuthenticated
    # 认证: from rest_framework.throttling import SimpleRateThrottle
    
    from rest_framework.views import APIView
    
    class Test(APIView):
    
        def get(self, request, *args, **kwargs):
            return Response('drf get ok')

    DRF请求生命周期

    1) 请求走的是APIView的as_view函数
    2) 在APIView的as_view调用父类(django原生)的as_view, 还禁用了csrf认证
    3) 在父类的as_view中dispatch方法请求走的又是APIView的dispatch
    4) 完成任务方法交给视图类的请求函数处理, 得到请求的响应结果, 返回给前台

    APIView(as_view())禁用csrf => View(as_view()) => APIView(dispatch()) => 视图类的请求方法 => 响应

    APIView的dispatch方法源码(四大模块)

    def dispatch(self, request, *args, **kwargs):
            """
            `.dispatch()` is pretty much the same as Django's regular dispatch,
            but with extra hooks for startup, finalize, and exception handling.
            """
            self.args = args
            self.kwargs = kwargs
            # 请求模块
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
            self.headers = self.default_response_headers  # deprecate?
    
            try:
                # 三大认证模块
                self.initial(request, *args, **kwargs)
    
                # Get the appropriate handler method
                if request.method.lower() in self.http_method_names:
                    handler = getattr(self, request.method.lower(),
                                      self.http_method_not_allowed)
                else:
                    handler = self.http_method_not_allowed
    
                response = handler(request, *args, **kwargs)
    
            except Exception as exc:
                # 异常模块
                response = self.handle_exception(exc)
    
            # 渲染模块
            self.response = self.finalize_response(request, response, *args, **kwargs)
            return self.response

    dispatch的请求模块: request对象

    APIView类中的dispatch方法中: request = self.initialize_request(request, *args, **kwargs)

    def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        request = self.initialize_request(request, *args, **kwargs)
        ...
    
    
    def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        parser_context = self.get_parser_context(request)
      
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

    1) drf对原始request做了二次封装, request._request就是原生的request
    2) 原生request对象的属性和方法都可以被drf的request对象直接访问(兼容)
    3) drf请求的所有url拼接参数均被解析到query_params中, 所有数据包都被解析到data中

    query_params和data的使用

    class Test(APIView):
    
        def get(self, request, *args, **kwargs):
            # url拼接的参数
            print(request._request.GET)  # 二次封装方式
            print(request.GET)  # 兼容
            print(request.query_params)  # 扩展
    
            return Response('drf get ok')
    
        def post(self, request, *args, **kwargs):
            # 所有请求方式携带的数据包
            print(request._request.POST)  # 二次封装方式
            print(request.POST)  # 兼容
            print(request.data)  # 扩展, 兼容性最强, 三种数据方式都可以
            
            print(request.query_params)
    
            return Response('drf post ok')

    dispatch的渲染模块: 浏览器和Postman请求结果渲染数据的方式不一样

    APIView类中的dispatch方法中:self.response = self.finalize_response(request, response, *args, **kwargs)

    1) # 渲染response入口
    self.response = self.finalize_response(request, response, *args, **kwargs)
    
    2) # 获取渲染模板的方法
    neg = self.perform_content_negotiation(request, force=True) 
    
    3) # 获取渲染类
    renderers = self.get_renderers()
    
    4) # 获取settings中配置的模板信息
    def get_renderers(self):
        return [renderer() for renderer in self.renderer_classes]
    
    5) # setting中的配置信息
    # 自定义drf配置
    REST_FRAMEWORK = {
        # drf提供的渲染类
        'DEFAULT_RENDERER_CLASSES': [
            'rest_framework.renderers.JSONRenderer',
            'rest_framework.renderers.TemplateHTMLRenderer',
        ],
    }

    全局配置与局部配置drf渲染类

    # 全局配置: settings文件中
    REST_FRAMEWORK = {
        # drf提供的渲染类
        'DEFAULT_RENDERER_CLASSES': [
            'rest_framework.renderers.JSONRenderer',
            'rest_framework.renderers.BrowsableAPIRenderer',
        ],
    }
    
    # 局部配置: 类视图中定义类属性
    renderer_classes = [JSONRenderer]

    DRF的APIView查找渲染类配置的路径

    自定义视图类 => APIView视图类 => 自定义DRF配置 => DRF默认配置

    dispatch的解析模块

    APIView类中的dispatch方法中: request = self.initialize_request(request, *args, **kwargs)

    1) # 请求解析模块入口
    request = self.initialize_request(request, *args, **kwargs)
    
    2) # 获取解析类
    parsers=self.get_parsers()
    
    3) # 获取settings中的parser配置信息
    def get_parsers(self):
        return [parser() for parser in self.parser_classes]
    
    4) # settings中的parser配置信息
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    ],

    全局配置与局部配置解析类

    # 全局配置: settings文件中
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    ]
        
    # 局部配置: 类视图中定义类属性
    parser_classes = [JSONParser]

    DRF的APIView查找解析类配置的路径

    自定义视图类 => APIView视图类 => 自定义DRF配置 => DRF默认配置

    dispatch的异常处理模块

    APIView类中的dispatch方法中: response = self.handle_exception(exc)

    1) # 异常处理模块入口
    response = self.handle_exception(exc)
    
    2) # 获取处理异常的句柄(方法)
    exception_handler = self.get_exception_handler()
    
    3) # 异常处理的结果
    response = exception_handler(exc, context)
    
    4) # 没有异常内容抛出异常信息
    if response is None:
        self.raise_uncaught_exception(exc)
    
    5) # 有异常内容, 返回异常内容
    return response

    为什么要自定义异常模块

    1. 所有经过drf的APIView的视图类产生的异常, 都可以提供异常处理方案

    2. drf默认提供了异常处理方案(rest_framework.views.exception_heandler), 但是处理范围有限

    3. drf提供的处理方案, 处理了的返回异常信息, 每处理的返回None(后续就是服务器抛异常给前台)

    4. 自定义异常的目的就是解决drf没有处理的异常, 让前台得到合理的异常信息, 后台记录异常具体信息

    自定义异常处理类的方案: 自定义exception_handler函数如何书写实体

    1) 现将异常处理交给rest_framework.views的exception_handler去处理

    2) 判断处理的结果(返回值)response, 有值代表drf已经处理, None代表需要自己去处理

    # 自定义异常就是提供exception_handler异常处理函数, 处理的目的就是让response一定有值
    
    # 1. 在app中创建exception.py文件
    
    # 2. 在exception.py文件中导入drf中异常处理方法exception_handler
    from rest_framework.views import exception_handler as drf_exception_handler
    
    # 3. 自定义异常处理函数
    def exception_handler(exc, context):
        # 使用drf的exception_handler()方法得到response
        response = drf_exception_handler(exc, context)
        
        # 如果response为None, 我们就给他赋值(达到异常处理的目的)
        if not response:
            # print(exc)
            # print(context)
    
            print('%s - %s - %s' % (context['view'].__class__, context['request'].method, exc))
    
            return Response({
                'detail': '服务器错误'
            })
        
        # 如果response有值, 则直接返回response对象
        return response
    
    # 4. 在项目的settings文件中导入自定义的drf异常处理模块
    'EXCEPTION_HANDLER': 'apiTwo.exception.exception_handler'

    响应处理模块

    响应模块源码分析

    from http.client import responses
    
    from django.template.response import SimpleTemplateResponse
    
    from rest_framework.serializers import Serializer
    
    class Response(SimpleTemplateResponse):
        def __init__(self, data=None, status=None,
                     template_name=None, headers=None,
                     exception=False, content_type=None):
            super().__init__(None, status=status)
    
            if isinstance(data, Serializer):
                msg = (
                    'You passed a Serializer instance as data, but '
                    'probably meant to pass serialized `.data` or '
                    '`.error`. representation.'
                )
                raise AssertionError(msg)
    
            self.data = data
            self.template_name = template_name
            self.exception = exception
            self.content_type = content_type
    
            if headers:
                for name, value in headers.items():
                    self[name] = value
    
        @property
        def rendered_content(self):
            renderer = getattr(self, 'accepted_renderer', None)
            accepted_media_type = getattr(self, 'accepted_media_type', None)
            context = getattr(self, 'renderer_context', None)
    
            assert renderer, ".accepted_renderer not set on Response"
            assert accepted_media_type, ".accepted_media_type not set on Response"
            assert context is not None, ".renderer_context not set on Response"
            context['response'] = self
    
            media_type = renderer.media_type
            charset = renderer.charset
            content_type = self.content_type
    
            if content_type is None and charset is not None:
                content_type = "{}; charset={}".format(media_type, charset)
            elif content_type is None:
                content_type = media_type
            self['Content-Type'] = content_type
    
            ret = renderer.render(self.data, accepted_media_type, context)
            if isinstance(ret, str):
                assert charset, (
                    'renderer returned unicode, and did not specify '
                    'a charset value.'
                )
                return ret.encode(charset)
    
            if not ret:
                del self['Content-Type']
    
            return ret
    
        @property
        def status_text(self):
            return responses.get(self.status_code, '')
    
        def __getstate__(self):
            state = super().__getstate__()
            for key in (
                'accepted_renderer', 'renderer_context', 'resolver_match',
                'client', 'request', 'json', 'wsgi_request'
            ):
                if key in state:
                    del state[key]
            state['_closable_objects'] = []
            return state
    View Code

    响应构造器

    def __init__(self, data=None, status=None,
                     template_name=None, headers=None,
                     exception=False, content_type=None):
        """
        Args:
            data: 响应数据
            status: http响应状态码
            template_name: drf也可以渲染页面, 渲染的页面模板地址(不用了解)
            headers: 响应头
            exception: 是否异常
            content_type: 响应的数据格式(一般不用处理, 响应头中带有, 且默认是json)
        """

    常规实例化响应对象

    from rest_framework import status
    
    return Response(data={数据}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True, headers={设置的响应头})
  • 相关阅读:
    liunx配置jdk
    liunx 用户修改文件打开数
    goolge安装插件
    安装解压版MySQL 5.6.35
    Windows7 搭建ftp 服务
    eclipse 搭建Swt 环境
    注释正则表达式
    java excle导出合计字段值
    liunx 字符编码问题
    FreeIPA ACI (Access Control Instructions) 访问控制说明
  • 原文地址:https://www.cnblogs.com/featherwit/p/13494471.html
Copyright © 2011-2022 走看看