Day85--drf06--整体流程及源码分析、全局异常处理与接口文档

技术Day85--drf06--整体流程及源码分析、全局异常处理与接口文档 Day85--drf06--整体流程及源码分析、全局异常处理与接口文档昨日回顾
1 频率限制-写一个类,继承SimpleRat

第85天-drf 06-整体流程和源代码分析、全局异常处理和接口文档

昨日回顾

1频率极限

-写一个类,继承SimpleRateThrottle,覆盖get_cache_key,

限制返回的内容(限制ip、限制用户id、移动电话号码),

-编写另一个类属性范围=“字符串”,它需要对应于配置文件中的“字符串”:“5/m”

-本地配置,全局配置

#注意:如果全局配置受ip限制,那么所有接口的总数不能超过指定的次数,这意味着它不仅仅是一定数量的接口。

2过滤和排序

-内置过滤器类:搜索过滤器

-内置排序类:排序过滤器

-在继承genericpiviewlistmodelmixin及其子类的视图接口中配置,类属性:filter _ backs=[]。

-配置相应的字段。

-search_fields=['name']

-ordering_fields=['price']

3第三方过滤类

-在类属性上配置:filter _ back ends=[djangoofilterback]

-配置字段:filter set _ field=[' name ',' price']

-http://127 . 0 . 0 . 1:8000/书/名=红楼梦价格=12

4自定义过滤器类别

-自己编写一个类,继承basefilter后端,覆盖filter_queryset,返回queryset对象,该对象经过过滤。

-配置为继承genericpiviewlistmodelmixin及其子类,类属性:filter_backends

5分页功能

-三个分页类

页码分页:基本分页页面=1size=2

-四个类别属性

限制偏移量分页:偏移量分页限制=3偏移量=2

-四个类别属性

光标分页:光标分页选择上一页和下一页。

-三类属性

-cursor_query_param='cursor' #查询条件

-page_size=2 #显示多少页?

-订购='id' #由谁订购

-只需要配置为继承genericpiviewlistmodelmixin及其子类,class属性:paging _ class。

今日内容

1. drf整体流程

# drf的位置:在进入视图类之前,路线匹配成功。

#整体处理流程:

1.包装新的请求对象。

2.处理编码(urlencoded、formdata、json)

3.三大认证(顺序:认证、权威和频率)(* * * * * *)

4.输入视图类:

-4.1在继承的情况下(API view)(* * * * * *)

-从模型中获取数据。

-序列化(* * * * *)

-返回数据

-4.2在继承的情况下(genericpivot listmodemmixin)(* * * *)

-从模型中获取数据。

-过滤和分类

-分页

-序列化(* * * * *)

-返回数据

-5.处理响应(浏览器、json)

-6.处理全局异常

2. 源码分析--认证、频率、权限

2.1 认证源码

# 1.入口:APIView-self . initial()-身份验证类:self.perform _ authentication(请求)的dispatch()中三个身份验证类的代码

# 2.自我。execute _authentication(请求)-即执行APIView的_ authentication()。

def execute _ authentication(self,request):

Request.user #实现新请求对象的user方法。

# 3.请求类的用户方法

@property

def用户(自我):

如果没有,请拨打:

with wrap _ attributeerrors():

#核心是这句话,是Request的_authenticate()方法。

自我。验证(_ e)

()
return self._user

# 4.Request类的_authenticate(self)方法 (核心)
def _authenticate(self):
for authenticator in self.authenticators: # self.authenticators是个列表,列表中放了一个个认证类的对象
try:
# self是request,所以自定义认证类的authenticate,有两个参数(self,request),第二个参数request给了这里的self
user_auth_tuple = authenticator.authenticate(self) # 执行认证类的authenticate方法
except exceptions.APIException:
self._not_authenticated()
raise

if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple # 解压赋值,后续的request对象就有user属性了
return
# 源码可知:若是写了多个认证类,只要有一个认证类中认证通过,返回了user和token,后续的认证类就不会for循环执行了
self._not_authenticated()

# 5.Request类的self.authenticators属性 是多个认证类对象的列表
-是在Request初始化的时候,传入的
-Request类是在什么时候初始化的---》APIView的dispatch中的刚开始位置
-APIView的dispatch()--- request = self.initialize_request(request, *args, **kwargs)

# 6.APIView的self.initialize_request方法
def initialize_request(self, request, *args, **kwargs):
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),# APIView的
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)

# 7.APIView的get_authenticators方法
def get_authenticators(self):
# 列表中放了一个个认证类的对象
return [auth() for auth in self.authentication_classes]

2.2 权限源码

# 1.入口:APIView的dispatch()中---self.initial()中处理三大认证---权限类的代码self.check_permissions(request)
# 2.APIView的check_permissions方法
    def check_permissions(self, request):
        for permission in self.get_permissions():  # 列表,是一个个视图类中配置的权限类的对象
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request,
                    message=getattr(permission, 'message', None),
                    code=getattr(permission, 'code', None)
                )
                
# 3.APIView的self.get_permissions():
    def get_permissions(self):
        # 列表里放了一个个权限类的对象
        return [permission() for permission in self.permission_classes]
    
# 4.权限认证失败,返回中文
	-在权限类中配置message即可(给对象,类都可以)

2.3 频率源码

# 1.入口:APIView的dispatch()中---self.initial()中处理三大认证---频率类的代码self.check_throttles(request)
# 2.APIView的self.check_throttles(request)
    def check_throttles(self, request):
        throttle_durations = []
        for throttle in self.get_throttles():  # 列表,是一个个视图类中配置的频率类的对象
            # 如果被限制了,就把剩余时间 追加到 throttle_durations 限制持续时间 列表中
            if not throttle.allow_request(request, self):
                throttle_durations.append(throttle.wait())  
                
# 3.APIView的self.get_throttles()
       def get_throttles(self):
        # 列表里放了一个个频率类的对象
        return [throttle() for throttle in self.throttle_classes]
    
# 从频率的源码可知:
若是自定义的频率类 是继承SimpleRateThrottle的,可以直接将限制的值 写在频率限制类中
	THROTTLE_RATES = {'ip_m_3': '3/m'}
    
    
    
# SimpleRateThrottle源码分析:
    def get_rate(self):  # 根据配置的限制值的key:scope,从THROTTLE_RATES中 取出限制值:rate
        """
        Determine the string representation of the allowed request rate.
        """
        if not getattr(self, 'scope', None):
            msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
                   self.__class__.__name__)
            raise ImproperlyConfigured(msg)
        try:
            return self.THROTTLE_RATES[self.scope]  # scope:'user' = '3/min'
        except KeyError:
            msg = "No default throttle rate set for '%s' scope" % self.scope
            raise ImproperlyConfigured(msg)
            
    def parse_rate(self, rate):  # 根据配置拆分出 限制次数 和 持续时间
        """
        Given the request rate string, return a two tuple of:
        allowed number of requests, period of time in seconds
        """
        if rate is None:
            return (None, None)
        # 3  m
        num, period = rate.split('/')  # rate:'3/min'
        num_requests = int(num)
        duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
        return (num_requests, duration)  
    
    def allow_request(self, request, view):
        if self.rate is None:
            return True
        # 当前登录用户的ip地址
        self.key = self.get_cache_key(request, view)  # key:'throttle_user_1'
        if self.key is None:
            return True
		
        # 从缓存中取出 存放IP访问时间 的列表,若是初次访问,缓存为空,self.history为[]
        self.history = self.cache.get(self.key, [])
        # 获取一下当前时间,存放到 self.now
        self.now = self.timer()
        # Drop any requests from the history which have now passed the throttle duration
		# 将时间列表中 超过持续时间的 全部删除
        
        # 当前访问与第一次访问时间间隔如果大于60s,将第一次记录清除,不再算作一次计数
        # self.history:[10:23,10:55]
        # now:10:56
        while self.history and  self.now - self.history[-1] = self.duration:
            self.history.pop()
        
        # history的长度与限制次数3进行比较
        # history 长度第一次访问0,第二次访问1,第三次访问2,第四次访问3失败
        if len(self.history) = self.num_requests:
            # 直接返回False,代表频率限制了
            return self.throttle_failure()
        # history的长度未达到限制次数3,代表可以访问
        return self.throttle_success()
    
    def throttle_success(self):  # 将当前时间插入到history列表的开头,将history列表、key、过期时间作为数据存到缓存中
        """
        Inserts the current request's timestamp along with the key into the cache.
        """
        self.history.insert(0, self.now)
        self.cache.set(self.key, self.history, self.duration)
        return True

3. 自定义全局异常处理

# 1.自定义一个全局异常处理函数
def common_exception_handler(exc, context):
	"""
	# 一般会将错误信息添加到日志:
    通过参数 exc可获取错误提示信息,通过参数context可获取错误详细信息
    str(exec)  # 错误提示信息
    str(context['view'])  # 错误发生的视图
    context['request'].META.get('REMOTE_ADDR')  # IP地址
    context['request'].user.id  # 用户的ID
	"""
    
    # 1. 执行drf默认的异常处理
    response = exception_handler(exc, context)
    # 2.判断是否能被默认的异常处理捕获
    if response:
        # 2.1 若能被默认的捕获到,会返回一个Response对象出来,我们可.data 拿出原本默认要返回给前端的数据,再结合自己的格式 指定返回
        return Response(data={'code': 9998, 'msg': response.data})
    else:
        # 2.2 若不能被默认的捕获到,会返回None,就自定义处理 返回给前端
        return Response(data={'code': 9999, 'msg': '服务器异常,请联系系统管理员'})
    
 # 2.在配置文件中
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'app01.exceptions.common_exception_handler', 
}

4. 自动生成接口文档

# 前后的分离
	-前端一批人
    	-根本不知道你写了什么接口,请求参数什么样,响应数据什么样
        -使用什么编码都不知道
    -后端一批人
    	-我们写了很多接口
        
        
# 需要写接口文档(不同公司有规范)
	-1 公司有接口文档平台,后端在平台上录入接口
    -2 使用第三方接口文档平台,后端写了在平台录入
    	-Yapi:开源
    -3 使用md,word文档写,写完传到git上
    -4 自动生成接口文档(swagger,coreapi)
    	-通过swagger自动生成后导出,再导入到Yapi中
        
# coreapi 第三方模块--自动生成接口文档
# 1 安装:pip install coreapi
# 2 在路由中配置
	from rest_framework.documentation import include_docs_urls
    urlpatterns = [
        ...
        path('docs/', include_docs_urls(title='站点页面标题'))
    ]
    
# 3 视图类:自动接口文档能生成的是继承自APIView及其子类的视图。
	-1) 单一方法的视图,可直接使用类视图的文档字符串,如
        class BookListView(generics.ListAPIView):
            """
            返回所有图书信息.
            """
    -2) 包含多个方法的视图,在类视图的文档字符串中,分开方法定义,如
        class BookListCreateView(generics.ListCreateAPIView):
            """
            get:
            返回所有图书信息.
            post:
            新建图书.
            """
    -3) 对于视图集ViewSet,仍在类视图的文档字符串中,分开定义,但是应使用action名称区分,如
        class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
            """
            list:
            返回图书列表数据
            retrieve:
            返回图书详情数据
            latest:
            返回最新的图书数据
            read:
            修改图书的阅读量
            """
        
# 4 在配置文件中配置       
REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
}

补充

1.函数显示传参类型和返回值

# python3.5以上版本,typing模块提高代码健壮性  (公司常见写的方式)
from typing import List, Tuple, Dict
def test(a: int, string: str, f: float, b: bool) - Tuple[List, Tuple, Dict, bool]:
    ll=[1,2,3,4]
    tup = (string, a, string)
    dic = {"xxx": f}
    boo = b
    return ll, tup, dic, boo
print(test(12, "lqz", 2.3, False))

作业

# 1 三个认证的源码---》自己捋一遍
# 2 写一个全局异常处理函数,保证无论出什么异常,前端都返回固定格式
def common_exception(exc, context):
    # 第一步:记录异常信息到日志
    print(
        f'异常视图:{str(context["view"])}  访问IP:{context["request"].META.get("REMOTE_ADDR")} '
        f'访问用户ID:{context["request"].user.id} 异常信息:{str(exc)}')
    # 第二步:调用rest_framework 的异常捕获
    response = exception_handler(exc, context)
    # 第三步:判断是否能被内置的捕获到
    if response:
        # 若能,将内部返回的数据取出来,再加上我们自己的格式 返回给前端
        return Response(data={'code': 9999, 'msg': response.data})
    return Response(data={'code': 99998, 'msg': '系统出错,请联系管理员'})
# 3 试一下coreapi自动生成接口文档
# 4 给你一个地址,上地址看看Yapi怎么用

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/143778.html

(0)

相关推荐

  • 网页图片,网页图片多少KB最适合

    技术网页图片,网页图片多少KB最适合网页图片10kb-50kb最适合网页图片。网页一般分两种,如果是网页源文件的话那就得看网页内容和程序的复杂,网页源文件因为都是代码,所以一般也就1KB左右。还有就是说被执行过的网页,也

    生活 2021年10月26日
  • mysql社区版和企业版的区别有哪些

    技术mysql社区版和企业版的区别有哪些这篇文章主要讲解了“mysql社区版和企业版的区别有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mysql社区版和企业版的区

    攻略 2021年12月2日
  • lob类型是什么意思(lob类型参数)

    技术LOB类型有哪些本篇内容主要讲解“LOB类型有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“LOB类型有哪些”吧!LOB相关的概念 LOB类型: 将信息文件(十进

    攻略 2021年12月22日
  • Android自定义View实现体重表盘的方法是什么

    技术Android自定义View实现体重表盘的方法是什么本篇内容介绍了“Android自定义View实现体重表盘的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如

    攻略 2021年11月1日
  • cssfloat浮动教程(css浮动属性float详解)

    技术CSS浮动float属性怎么使用这篇文章主要讲解了“CSS浮动float属性怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CSS浮动float属性怎么使用”吧

    攻略 2021年12月21日
  • git克隆失败怎么解决

    技术git克隆失败怎么解决这篇文章主要讲解了“git克隆失败怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“git克隆失败怎么解决”吧!

    攻略 2021年11月29日