自定义频率类
# 自定义的逻辑 1)取出访问者ip {192.168.1.12:[访问时间3,访问时间2,访问时间1],192.168.1.12:[],192.168.1.14:[]} 2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走 3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间, 4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过 5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
具体实现
from rest_framework.throttling import BaseThrottle class MyThrottling(): VISIT_RECORD = {} def __init__(self): self.history = None def allow_request(self, request, view): # (1)取出访问者ip ip = request.META.get('REMOTE_ADDR') import time ctime = time.time() # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问 if ip not in self.VISIT_RECORD: self.VISIT_RECORD[ip] = [ctime, ] return True self.history = self.VISIT_RECORD.get(ip) # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间, while self.history and ctime - self.history[-1] > 60: self.history.pop() # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过 # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败 if len(self.history) < 3: self.history.insert(0, ctime) return True else: return False def wait(self): import time ctime = time.time() return 60 - (ctime - self.history[-1])
权限,频率执行源码分析
权限源码执行流程 # APIView的dispatch---》self.initial(request, *args, **kwargs)---》415行self.check_permissions(request)---> 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) ) 频率源码执行流程 # APIView的dispatch---》self.initial(request, *args, **kwargs)---》416行self.check_throttles(request)---> def check_throttles(self, request): throttle_durations = [] for throttle in self.get_throttles(): # 配在视图类上频率类列表 频率类的对象 if not throttle.allow_request(request, self): throttle_durations.append(throttle.wait()) if throttle_durations: durations = [ duration for duration in throttle_durations if duration is not None ] duration = max(durations, default=None) self.throttled(request, duration) # 你写的频率类一定要重写allow_request,返回True就是没有频率限制住,返回False就是被频率限制了 # 咱们第一天写的,继承SimpleRateThrottle---》它肯定重写了allow_request---》今天写的逻辑跟源码一样 SimpleRateThrottle---》allow_request---》 def __init__(self): if not getattr(self, 'rate', None): # self.rate 现在是 '3/m' self.rate = self.get_rate() # 3 60 self.num_requests, self.duration = self.parse_rate(self.rate) def allow_request(self, request, view): if self.rate is None: # 只要配在文件配了,它就有值,在init中 return True # 现在的唯一字符串 # ip地址 self.key = self.get_cache_key(request, view) if self.key is None: return True # [时间2,时间1] self.history = self.cache.get(self.key, []) self.now = self.timer() while self.history and self.history[-1] <= self.now - self.duration: self.history.pop() #把所有超过60的数据都剔除,self.history只剩60s以内的访问时间 if len(self.history) >= self.num_requests: #大于等于配置的数字3 return self.throttle_failure() # return False return self.throttle_success() # 把当前时间插入,retrun True
全局异常处理
drf配置文件中,已经配置了,但是它不符合咱们的要求 drf的配置文件:'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler', 如果抛了异常,就会执行exception_handler函数 重新写一个函数,如果出了异常,执行我们的函数 drf默认的异常处理,只处理了drf自己的异常:所有drf中抛的异常,都有detail,django的异常,抛出很长的xml数据 { "detail": "小伙子,你错了" } { code:999 msg:"小伙子,你错了" }
使用步骤
# 第一步:写一个函数 from rest_framework.views import exception_handler from rest_framework.response import Response def common_exception_handler(exc, context): # 正常来讲,在这里需要记录日志---》如何在django中记录日志后面讲 # 日志记录,越详细越好:哪个用户(id,ip),在什么时间,执行哪个视图函数时报了错,请求地址是什么 print(context['view']) #视图类的对象 print(context['request']) #当前请求的对象----》ip,用户id,当前时间,请求地址来 view=context['view'] request=context['request'] print('ip地址为:%s的用户,访问:%s 视图类,报错了,请求地址是:%s'%(request.META.get('REMOTE_ADDR'),str(view),request.path)) response=exception_handler(exc, context) if response: # 这是drf的异常,其实人家已经处理了,但是不符合我的格式 {code:999,msg:错误} res=Response({'code':999,'msg':response.data.get('detail')}) else: # res=Response({'code':998,'msg':'服务器错误,请联系系统管理员'}) res=Response({'code':998,'msg':str(exc)}) return res # 第二步:把函数配置在配置文件中 REST_FRAMEWORK = { # 自己写的全局异常捕获 'EXCEPTION_HANDLER': 'app01.exceptions.common_exception_handler', }
自动生成接口文档
# 后端人员,写好接口,提供接口文档给前端用 # 如何编写接口文档 -使用word写,md写----》提交到git上 -公司有接口文档平台---》后端人员在文档平台录入数据---》公司自己开发,yapi(百度开源),第三方 -https://zhuanlan.zhihu.com/p/366025001 自己搭建yapi -https://www.showdoc.com.cn/ 第三方平台 - 自动生成接口文档---》项目写好了,一键生成接口文档----》一键生成---》导出---》导入到yapi # drf中自动生成接口文档 -coreapi,swagger(更通用一些,go,java) -安装 pip3 install coreapi -在项目中配置 -加入路由: from rest_framework.documentation import include_docs_urls urlpatterns = [ path('docs/', include_docs_urls(title='站点页面标题')) ] -配置文件中配置 REST_FRAMEWORK = { 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', } -尽管写接口,写注释,会自动生成
RBAC
# RBAC 是基于角色的访问控制(Role-Based Access Control )在 RBAC 中, 权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便 # 这种设计,在公司内部系统用的多,对外的系统基本不用 # 权限:真正的权限,比如发工资,招人,申请测试机 # 角色:(组,部门) 角色下有很多员工 # 用户:一个个的人 # 用户和角色关系是多对多,中间表 # 权限和角色关系是多对多,中间表 # 权限和用户的中间表 #前后端分离项目控制权限---》权限类中 #前后端混合 -django框架在公司里用的很多,写内部项目,肯定要用权限控制,用的就是rbac,自己实现一套,django内置了后台管理,自带rbac(admin+auth) -基于django的admin二次开发 -美化:xadmin(基本不用了,2.x以后django不兼容多,作者弃坑了) -simpleui: -django+drf+vue=djagnovueadmin 一款前后端分离的自带rbac的后台管理框架 # django的admin基于rbac -auth_user #用户表 -auth_permission #权限表 -auth_group #组,角色表 -auth_user_groups # 用户和组中间表 -auth_group_permissions #组和权限中间表 -auth_user_user_permissions #用户和权限中间表
标签:自定义,ip,self,request,---,源码,频率,权限,history From: https://www.cnblogs.com/wql0817/p/16617456.html