一、drf框架的封装特点

drf一定要在settings中注册和配置

如何自定义配置drf:

# settings.py
# drf框架自定义配置
REST_FRAMEWORK = {
# 全局配置解析类:适用于所有视图类
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser', # 对应json格式
'rest_framework.parsers.FormParser', # 对应url_encoding格式(form表单)
'rest_framework.parsers.MultiPartParser' # 对应forn_data格式(文件之类)
],
# 全局配置渲染类:适用于所有视图类
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
# 'rest_framework.renderers.BrowsableAPIRenderer', # 上线后尽量关闭
],
# 异常模块:异常处理函数
# 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
'EXCEPTION_HANDLER': 'api.exception.exception_handler',
}

drf的模块封装非常的规范,名词定义非常的严谨

import rest_framework
from rest_framework.views import APIView
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.exceptions import APIException
from rest_framework.pagination import PageNumberPagination
from rest_framework.settings import APISettings
from rest_framework.parsers import JSONParser
from rest_framework.filters import OrderingFilter

1、APIView类

APIView的请求的生命周期

  1. urls.py中路由调用自定义资源类的as_view方法;

  2. 系统会从自定义资源类中搜索as_view方法,但发现没有,于是会从自定义资源类的父类APIView中搜索as_view方法,发现可以找到,于是调用;

  3. 因为APIView类继承View类,所以其实它是重写了as_view方法;

  4. 在APIView类中重写as_view方法:

    1. 判断了当前自定义类实例化出来的对象是否是一个queryset对象,如果是就报错;
    2. 如果不是,就会获取父类(View类)的as_view方法的函数地址并赋值给名为view的变量;
    3. 将自定义类及其实例化对象的参数计入变量view的名称空间,让其可以调用,然后用函数将view即将通过的csrf认证组件禁用,再将处理后的view变量返回给路由,这样客户端访问该url时,就会直接调用这个处理后的view变量。
    # rest_framework的views.py文件
    def as_view(cls, **initkwargs):
    """
    Store the original class on the view function. This allows us to discover information about the view when we do URL
    reverse lookups. Used for breadcrumb generation.
    """
    if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
    def force_evaluation():
    raise RuntimeError(
    'Do not evaluate the `.queryset` attribute directly, '
    'as the result will be cached and reused between requests. '
    'Use `.all()` or call `.get_queryset()` instead.'
    )
    cls.queryset._fetch_all = force_evaluation view = super().as_view(**initkwargs)
    view.cls = cls
    view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated,
    # all other authentication is CSRF exempt.
    return csrf_exempt(view)
  5. 当客户端访问路由时,view变量对应的View.as_view方法调用,并且在调用时获取了view变量的名称空间中携带的自定义类其实例化对象的参数

    # django\views\generic\base.py
    @classonlymethod
    def as_view(cls, **initkwargs):
    """
    Main entry point for a request-response process.
    """
    for key in initkwargs:
    if key in cls.http_method_names:
    raise TypeError("You tried to pass in the %s method name as a "
    "keyword argument to %s(). Don't do that."
    % (key, cls.__name__))
    if not hasattr(cls, key):
    raise TypeError("%s() received an invalid keyword %r. as_view "
    "only accepts arguments that are already "
    "attributes of the class." % (cls.__name__, key)) def view(request, *args, **kwargs):
    self = cls(**initkwargs)
    if hasattr(self, 'get') and not hasattr(self, 'head'):
    self.head = self.get
    self.request = request
    self.args = args
    self.kwargs = kwargs
    return self.dispatch(request, *args, **kwargs)
    view.view_class = cls
    view.view_initkwargs = initkwargs # take name and docstring from class
    update_wrapper(view, cls, updated=()) # and possible attributes set by decorators
    # like csrf_exempt from dispatch
    update_wrapper(view, cls.dispatch, assigned=())
    return view

    发现函数内调用了self.dispatch函数;

  6. 所以去self也就是自定义类中找dispatch方法,而自定义类中没有dispatch方法,于是就从父类APIView类中找,确实找到了;

  7. 因为APIView类继承View类,所以其实它是重写了dispatch方法;

  8. 重写的dispatch方法:

    1. 在执行请求逻辑前:请求模块(二次封装request)、解析模块(三种数据包格式的数据解析)
    2. 在执行请求逻辑中:进行三大认证,通过则正常响应;不通过就进入异常模块(执行出现任何异常就会交给异常模块处理)
    3. 在执行请求逻辑后:响应模块(二次封装response)、渲染模块(响应的数据能用JSON和HTML页面两种方式渲染) 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对象,包含解析模块
    request = self.initialize_request(request, *args, **kwargs)
    self.request = request
    self.headers = self.default_response_headers # deprecate? try:
    # 三大认证(认证、权限、频率),用来替换csrf安全认证,要比csrf认证强大得多
    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)
    # 二次封装response,处理了结果渲染
    self.response = self.finalize_response(request, response, *args, **kwargs)
    return self.response

二、drf的基础组件

1、请求模块

1.1 请求模块做了什么

  1. 将wsgi的request对象二次封装转化成drf的request对象;

  2. 封装后的request对象完全兼容wsgi的request对象,并且将原request对象保存在新request._request中;

  3. 重新格式化数据。请求数据存放位置:

    • 拼接参数:request.query_params
    • 数据包参数:request.data
  4. 源码分析:

    # dispatch中会对request进行二次封装:
    # request = self.initialize_request(request, *args, **kwargs)
    # 调用了initialize_request()函数
    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
    ) # 可见在函数中将wsgi的request对象用drf的Request类进行了二次封装 class Request:
    # 部分代码
    def __init__(self, request, parsers=None, authenticators=None...) self._request = request
    self.parsers = parsers or ()
    self.authenticators = authenticators or ()
    self.negotiator = negotiator or self._default_negotiator()
    self.parser_context = parser_context
    self._data = Empty # Empty为空类,仅仅用作替代,
    self._files = Empty # 相当于None
    self._full_data = Empty
    self._content_type = Empty
    self._stream = Empty

1.2 请求request参数

request.data:
request.data 返回请求正文的解析内容。
它与request.POST 和 request.FILES 属性类似,
除了下面的:
1.它包括所有解析的内容, 包括 文件或非文件 输入。
2.它支持解析除POST之外的HTTP方法的内容,这意味着你可以访问PUT和PATCH请求的内容。
3.它支持REST framework灵活的请求解析,而不仅仅支持表单数据。 例如,你可以以与处理传入表单数据相同的方式处理传入的JSON数据。 request.query_params:
request.query_params是request.GET的一个更准确的同义词。
为了让你的代码清晰明了, 我们建议使用 request.query_params 而不是Django标准的request.GET。
这样做有助于保持代码库更加正确和明了——任何HTTP方法类型可能包括查询参数,而不仅仅是GET请求。 request.parsers

2、解析模块

settings配置文件中注册:

REST_FRAMEWORK = {
# 全局配置解析类:适用于所有视图类
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
],
}

view视图文件中导入解析模块

from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
# 局部配置
class BookAPIView(APIView):
# 局部配置解析类:只适用当前视图类
parser_classes = [JSONParser, FormParser, MultiPartParser]

解析模块只处理数据包参数。

参数格式有三种:form-data,urlencoded,json

  1. 全局配置所有视图类的解析方式,解析配置可以配置三种
  2. 局部配置当前视图类的解析方式,解析配置可以配置三种
  3. 配置的查找顺序:局部(视图类)->全局(settings文件中的drf配置)->默认(drf的默认配置)

注:该模块了解,但全局局部配置是重点

  1. 源码分析

    # dispatch对request进行二次封装中:
    request = self.initialize_request(request, *args, **kwargs) # initialize_request
    parsers=self.get_parsers() # get_parsers
    return [renderer() for renderer in self.renderer_classes]

3、响应模块

views视图函数中使用响应模块:

from rest_framework.response import Response
class BookAPIView(APIView):
def get(self, request, *args, **kwargs):
response = Response(
data={
'msg': 'apiview get ok'
},
status=status.HTTP_404_NOT_FOUND,
)
return response

data:响应数据

status:响应的网络状态码

template_name:drf完成前后不分离返回页面,但是就不可以返回data(不需要了解)

headers:响应头,一般不规定,走默认

exception:一般异常响应会将其设置成True,默认为False(不设置也没事)

content_type:默认就是application/json,不需要处理。

4、渲染模块(了解)

settings配置文件中配置:

# drf框架自定义配置
REST_FRAMEWORK = {
# 全局配置渲染类:适用于所有视图类
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
# 上线后尽量关闭
# 'rest_framework.renderers.BrowsableAPIRenderer',
],
}

postman请求结果是json,浏览器请求结果是页面。

可以局部与全局配置。

5、异常模块

settings配置文件中配置:

REST_FRAMEWORK = {
# 异常模块:异常处理函数
# drf处理
# 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
# 自定义处理
'EXCEPTION_HANDLER': 'api.exception.exception_handler',
}

然后在app应用文件夹下创建处理异常的py文件:

# exception.py
# 一定要在settings文件中将异常模块配置自己的异常处理函数
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response def exception_handler(exc, context):
response = drf_exception_handler(exc, context)
detail = '%s - %s - %s' % (context.get('view'), context.get('request').method, exc)
if not response: # 服务端错误
response = Response({'detail': detail})
else:
response.data = {'detail': detail} # 核心:要将response.data.get('detail')信息记录到日志文件
# logger.waring(response.data.get('detail')) return response

网络异常状态码:

from rest_framework.status import *

HTTP_100_CONTINUE = 100
HTTP_101_SWITCHING_PROTOCOLS = 101
HTTP_200_OK = 200
HTTP_201_CREATED = 201
HTTP_202_ACCEPTED = 202
HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203
HTTP_204_NO_CONTENT = 204
HTTP_205_RESET_CONTENT = 205
HTTP_206_PARTIAL_CONTENT = 206
HTTP_207_MULTI_STATUS = 207
HTTP_208_ALREADY_REPORTED = 208
HTTP_226_IM_USED = 226
HTTP_300_MULTIPLE_CHOICES = 300
HTTP_301_MOVED_PERMANENTLY = 301
HTTP_302_FOUND = 302
HTTP_303_SEE_OTHER = 303
HTTP_304_NOT_MODIFIED = 304
HTTP_305_USE_PROXY = 305
HTTP_306_RESERVED = 306
HTTP_307_TEMPORARY_REDIRECT = 307
HTTP_308_PERMANENT_REDIRECT = 308
HTTP_400_BAD_REQUEST = 400
HTTP_401_UNAUTHORIZED = 401
HTTP_402_PAYMENT_REQUIRED = 402
HTTP_403_FORBIDDEN = 403
HTTP_404_NOT_FOUND = 404
HTTP_405_METHOD_NOT_ALLOWED = 405
HTTP_406_NOT_ACCEPTABLE = 406
HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407
HTTP_408_REQUEST_TIMEOUT = 408
HTTP_409_CONFLICT = 409
HTTP_410_GONE = 410
HTTP_411_LENGTH_REQUIRED = 411
HTTP_412_PRECONDITION_FAILED = 412
HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413
HTTP_414_REQUEST_URI_TOO_LONG = 414
HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416
HTTP_417_EXPECTATION_FAILED = 417
HTTP_418_IM_A_TEAPOT = 418
HTTP_422_UNPROCESSABLE_ENTITY = 422
HTTP_423_LOCKED = 423
HTTP_424_FAILED_DEPENDENCY = 424
HTTP_426_UPGRADE_REQUIRED = 426
HTTP_428_PRECONDITION_REQUIRED = 428
HTTP_429_TOO_MANY_REQUESTS = 429
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451
HTTP_500_INTERNAL_SERVER_ERROR = 500
HTTP_501_NOT_IMPLEMENTED = 501
HTTP_502_BAD_GATEWAY = 502
HTTP_503_SERVICE_UNAVAILABLE = 503
HTTP_504_GATEWAY_TIMEOUT = 504
HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505
HTTP_506_VARIANT_ALSO_NEGOTIATES = 506
HTTP_507_INSUFFICIENT_STORAGE = 507
HTTP_508_LOOP_DETECTED = 508
HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509
HTTP_510_NOT_EXTENDED = 510
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511

DRF的封装:APIView类及五大模块的更多相关文章

  1. DRF框架(五)——context传参,二次封装Response类,两个视图基类(APIView/GenericAPIView),视图扩展类(mixins),子类视图(工具视图),视图集(viewsets),工具视图集

    复习 1.整体修改与局部修改 # 序列化get (给前端传递参数) #查询 ser_obj = ModelSerializer(model_obj) #只传递一个参数,默认是instance的参数,查 ...

  2. drf:restful概念,类继承关系,drf请求封装,drf请求流程,版本控制组件,认证组件(token),权限组件

    1.restful规范 resfful规范的概念最重要: 是一套规范,规则,用于程序之间进行数据交换的约定. 他规定了一些协议,对我们感受最直接的就是,以前写增删改查的时候需要些四个视图寒素,rest ...

  3. rest_framework五大模块

    面向对象封装 面向对象封装导入 # 1.将子类共有的方法抽离形成父类方法 # 2.子类使用共有方法,使用的是父类方法 # 3.共有方法中的资源,在子类使用方法时,获取的是子类资源 class MyCl ...

  4. DRF介绍,DRF项目开发,DRF项目的视图类的dispatch源码解析

    目录 一.DRF介绍 1. 什么是DRF 2. 为什么要用DRF (1)使用DRF的原因 (2)站在开发者的角度来说用DRF的好处(暂时列举这么多) 二.用DRF开发后端项目 三.APIView请求生 ...

  5. drf安装与APIView初步分析

    drf安装 1. pip install djangorestframework 2. 在settings文件中注册app : INSTALLED_APPS = [..., 'rest_framewo ...

  6. 探索drf执行流程之APIView源码分析

    Django REST framework 简介 现在新一代web应用都开始采用前后端分离的方式来进行,淘汰了以前的服务器端渲染的方式.而实现前后端分离是通过Django REST framework ...

  7. 封装application类

    <?php  //判断用户是否是通过入口文件访问   if(!defined('ACCESS')){     echo '非法请求';     die;   }   //封装初始化类   cla ...

  8. Asp.Net Core 2.0 项目实战(6)Redis配置、封装帮助类RedisHelper及使用实例

    本文目录 1. 摘要 2. Redis配置 3. RedisHelper 4.使用实例 5. 总结 1.  摘要 由于內存存取速度远高于磁盘读取的特性,为了程序效率提高性能,通常会把常用的不常变动的数 ...

  9. python 日志的配置,python对日志封装成类,日志的调用

    # python 日志的配置,python对日志封装成类,日志的调用 import logging # 使用logging模块: class CLog: # --------------------- ...

随机推荐

  1. Redis命令之setbit

    setbit的作用是,对key上存储的字符串,设置或清除指定偏移量上的位(bit). 语法如下: SETBIT key offset value key是要操作的对象的键. offset是操作对象上的 ...

  2. hdu5726 GCD(gcd +二分+rmq)

    Problem Description Give you a sequence of N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000). ...

  3. P3803 [模板] 多项式乘法 (FFT)

    Rt 注意len要为2的幂 #include <bits/stdc++.h> using namespace std; const double PI = acos(-1.0); inli ...

  4. 使用scrapy爬取jian shu文章

    settings.py中一些东西的含义可以看一下这里 python的scrapy框架的使用 和xpath的使用 && scrapy中request和response的函数参数 & ...

  5. HDU 2176 取(m堆)石子游戏 && HDU1850 Being a Good Boy in Spring Festivaly

    HDU2176题意: m堆石子,两人轮流取.只能在1堆中取.取完者胜.先取者负输出No.先取者胜输出Yes,然后输出怎样取子. 通过 SG定理 我们可以知道每一个数的SG值,等于这个数到达不了的前面数 ...

  6. 2019牛客暑期多校训练营(第八场)B Beauty Values && C CDMA

    B题题意: 题目 给你n个数,让你把这一个序列中的所有子区间的Beauty Values加起来,Beauty Values是子区间内有几个不同的数 题解: 肯定不会是暴力,所以我们就要在各元素的位置上 ...

  7. AtCoder Beginner Contest 182 D - Wandering (前缀和)

    题意:在\(x\)轴上,你刚开始在\(0\)的位置,第\(i\)次操作需要走\(A_1,...,A_i\)个单位,如果\(A_i\)为正向右走,否则向左走,求你所能走到的最大坐标. 题解:我们一步一步 ...

  8. .net面试--值类型和引用类型

    注:下面的示意图主要是为了辅助理解,不代表内存真实情况. Introduction 类型基础是C#的基础概念,了解类型基础及背后的工作原理更有助于我们在编码的时候明白数据在内存中的分配与传递.C#提供 ...

  9. 5.PowerShell DSC核心概念之资源

    什么是资源? 资源为 DSC 配置提供构建基块. 资源公开可配置的属性,并包含本地配置管理器 (LCM) 调用以"使其如此"的 PowerShell 脚本函数. 系统内置资源 可在 ...

  10. JVM调优参数、方法、工具以及案例总结

    这种文章挺难写的,一是JVM参数巨多,二是内容枯燥乏味,但是想理解JVM调优又是没法避开的环节,本文主要用来总结梳理便于以后翻阅,主要围绕四个大的方面展开,分别是JVM调优参数.JVM调优方法(流程) ...