限流
DRF 限流原理:
匿名用户,使用ip地址标识访问者,存储每次访问的时间节点。
缓存: throttle_anon_ip<==> [时间戳1,时间戳2,…]
判断历史访问时间节点的长度 >= 限流次数,则拒绝;
每次请求过来时,查看self.history中是否有访问历史,若没有,则允许访问,并存储当前访问的时间节点self.history.inser(0, self.now);若有访问历史,先查看是否有过期的记录self.history[-1] <= self.now-self.duration,有则删除,然后判断访问次数是否超限len(self.history)。(及时循环删除过期的访问节点)
# 全局配置
# 全局配置
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
# 限制所有匿名未认证用户,使用IP区分用户
'rest_framework.throttling.AnonRateThrottle',
# 限制认证用户
'rest_framework.throttling.UserRateThrottle'
),
# 配置限流频率
'DEFAULT_THROTTLE_RATES': {
# 可以使用 second, minute, hour 或day来指明周期
# 匿名用户,每分钟3次请求
'anon': '3/minute',
# 认证用户,每分钟5次请求
'user': '5/minute'
}
}
分页
- 分页的简单使用
from rest_framework.pagination import PageNumberPagination
class MyPagination(PageNumberPagination):
page_size = 5 # 默认每页的条数
max_page_size = 6 # 最多每页条数
page_query_param = "page" # 页码的查询参数
page_size_query_param = "pagesize" # 查询参数中的每页显示的条数, 以此为准
# 用户信息视图
class UserInfoViewSet(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSer
pagination_class = MyPagination
2. 分页的重写
from django.core.paginator import InvalidPage
# 重写 分页方法
class MyPagination(PageNumberPagination):
"""全局的分页,所有的list请求都会调用"""
# 默认每页显示的条数,前端不传参数时,默认
page_size = 10
max_page_size = 20 # 每页最大显示的条数
#页码 参数 如 /users/?page=2&pagesize=3
page_query_param = "page"
page_size_query_param = 'pagesize' # 前端发送的页数关键字名
# 可以重写分页的方法
def paginate_queryset(self, queryset, request, view=None):
"""
Paginate a queryset if required, either returning a
page object, or `None` if pagination is not configured for this view.
"""
empty = True
# 请求的分页 每页条数
page_size = self.get_page_size(request)
if not page_size:
# 没有要求分页,返回None
return None
paginator = self.django_paginator_class(queryset, page_size)
# 获取页码
page_number = request.query_params.get(self.page_query_param, 1)
# 最后一页
if page_number in self.last_page_strings:
page_number = paginator.num_pages
try:
self.page = paginator.page(page_number)
except InvalidPage as exc:
empty = False
if paginator.num_pages > 1 and self.template is not None:
# The browsable API should display pagination controls.
self.display_page_controls = True
self.request = request
if not empty: # 出异常
self.page = []
return list(self.page)
def get_paginated_response(self, data): # 传入当前分页的数据
return Response(OrderedDict([
('count', self.page.paginator.count if self.page else 0),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('code', 0),
('message', 'Ok'),
('results', data),
]))
模型类
from django.contrib.auth.models import AbstractUser
from django.db import models
# 用户模型类
class User(AbstractUser):
mobile = models.CharField("手机号", max_length=11)
user_type = models.ForeignKey(UserRole, on_delete=models.CASCADE, verbose_name="用户角色")
# 角色模型类
class UserRole(models.Model):
ROLES = (
(1, "普通会员"),
(2, "黄金会员"),
(3, "白金会员"),
(4, "钻石会员")
)
role = models.IntegerField("角色", choices=ROLES)
# API 地址表
class Urls(models.Model):
url = models.CharField("路由地址", max_length=200)
visit_role = models.ManyToMany(Role)
DRF的权限
局部鉴权
from rest_framework.permissions import BasePermission
from rest_framework.permissions import IsAuthenticated # 是否登录
from rest_framework.throttling import BaseThrottle # 访问频率
class MyPermission(BasePermission)
def has_permission(self, request, view):
# 权限校验通过
return True
#否则 return False
# 局部认证、鉴权、限流
class CheckView(APIView):
pagination_class = MyPagination
authentication_classes = [MyAuthentication,]
permission_classes = (IsAuthenticated, MyPermission)
throttle_classes = []
queryset = User.objects.all()
serializer_class = UserSer
全局鉴权
from rest_framework.permissions import BasePermission
import re
class MyPermission(BasePermission):
def has_permission(self, request, view):
# view为对应的要进入的视图
print("我的认证权限类:", view)
# 权限认证,忽略登录的视图
if re.findall(r"login|admin", request.path_info, re.I):
return True
# 会话保持认证通过,会有request.user
# 这里先查询用户
user = User.objects.filter(id=1).first()
for i in user.role.all():
if i.name == "管理员":
# 有权限访问
return True
else: # 循环正常结束时,执行
return False
全局配置rest_framework的鉴权
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": ('users.utils.MyPermission'),
}