Django rest framework之限流Throttling、内置过滤功能及第三方过滤功能及分页Pagination

1、限流Throttling

可以对接口访问的频次进行限制,以减轻服务器压力
一般用于付费购买次数,投票等场景使用

1.1、自定义频率类
1.1.1、编写频率类
# 自定义的逻辑
#(1)取出访问者ip
#(2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
#(3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
#(4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
#(5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
class MyThrottles():
    VISIT_RECORD = {}
    def __init__(self):
        self.history=None
    def allow_request(self,request, view):
        #(1)取出访问者ip
        # print(request.META)
        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])
1.1.2、全局使用
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES':['app01.utils.MyThrottles',],
}
1.1.3、局部使用
# 在视图类里使用
throttle_classes = [MyThrottles,]
1.2、内置频率类
1.2.1、根据用户ip限制
# 写一个类,继承自SimpleRateThrottle(根据ip限制)
from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
    scope = 'xxx'
    def get_cache_key(self, request, view):
        return self.get_ident(request)
#在setting里配置: (一分钟访问三次)
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES':{
        'xxx':'3/m'  # key要跟类中的scop对应
    }
}
# 可以全局使用,局部使用

了解:错误信息中文显示

class Course(APIView):
    authentication_classes = [TokenAuth, ]
    permission_classes = [UserPermission, ]
    throttle_classes = [MyThrottles,]

    def get(self, request):
        return HttpResponse('get')

    def post(self, request):
        return HttpResponse('post')
    def throttled(self, request, wait):
        from rest_framework.exceptions import Throttled
        class MyThrottled(Throttled):
            default_detail = 'xxx'
            extra_detail_singular = '还有 {wait} second.'
            extra_detail_plural = '出了 {wait} seconds.'
        raise MyThrottled(wait)
1.2.2、限制匿名用户每分钟访问3次
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '3/m',
    }
}
# 使用 `second`, `minute`, `hour` 或`day`来指明周期。
# 可以全局使用,局部使用
1.2.3、限制登陆用户每分钟访问10次
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'user': '10/m'
    }
}
# 可以全局使用,局部使用
1.2.4、其他
1.2.4.1、AnonRateThrottle
限制所有匿名未认证用户,使用IP区分用户
使用DEFAULT_THROTTLE_RATES['anon'] 来设置频次
1.2.4.2、UserRateThrottle
限制认证用户,使用User id 来区分
使用DEFAULT_THROTTLE_RATES['user'] 来设置频次
1.2.4.3、ScopedRateThrottle
限制用户对于每个视图的访问频次,使用ip或user id

class ContactListView(APIView):
    throttle_scope = 'contacts'
    ...

class ContactDetailView(APIView):
    throttle_scope = 'contacts'
    ...

class UploadView(APIView):
    throttle_scope = 'uploads'
    ...
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.ScopedRateThrottle',
    ),
    'DEFAULT_THROTTLE_RATES': {
        'contacts': '1000/day',
        'uploads': '20/day'
    }
}
1.2.5、全局配置中设置访问频率
'DEFAULT_THROTTLE_RATES': {
    'anon': '3/minute',
    'user': '10/minute'
}
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView
from rest_framework.throttling import UserRateThrottle

class StudentAPIView(RetrieveAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]
    throttle_classes = (UserRateThrottle,)
1.2.6、内置频率类使用总结
1、使用
	局部使用
    	throttle_classes = [auth.MyThrottle,]
    全局使用
    	REST_FRAMEWORK = {
    		'DEFAULT_THROTTLE_CLASSES':['app01.auth.MyThrottle',],
		}
		
2、内置频率类
    BaseThrottle: 基类
	AnonRateThrottle: 限制匿名用户的访问次数
    SimpleRateThrottle: 咱么自定义扩写它
    ScopedRateThrottle
    UserRateThrottle: 限制登录用户访问次数
    
3、扩展内置频率类
	定义一个类,继承SimpleRateThrottle
    class MySimpleThrottle(SimpleRateThrottle):
        scope = 'xxx'
        def get_cache_key(self, request, view):
            # 以ip限制
            return self.get_ident(request)
            
    在setting.py中配置
    	REST_FRAMEWORK = {
            'DEFAULT_THROTTLE_RATES' : {
                'xxx':'10/m'  # key跟scope对应,value是一个时间
            }
        }
	可以在局部使用和全局使用
    	
4、源码分析
	继承SimpleRateThrottle ---> allow_request
       
5、其它内置频率类
	限制未登录用户的频率(AnonRateThrottle)(根据ip限制)
    使用:
         局部使用,全局使用
         setting.py中配置
            'DEFAULT_THROTTLE_RATES' : {
     			'anon':'1/m'
    	 }
    	 
    限制登录用户访问次数UserRateThrottle(根据用户id限制)
    使用:
         局部使用,全局使用
         setting.py中配置
         'DEFAULT_THROTTLE_RATES' : {
            'user':'1/m'
         }

2、内置过滤功能及第三方过滤功能

2.1、内置过滤功能
过滤: 筛选查询结果
内置筛选的使用

在视图类中配置:
   from rest_framework.filters import SearchFilter
   filter_backends =[SearchFilter,]
   search_fields=('name',)  # 表模型中的字段
   
查询的时候:
   http://127.0.0.1:8000/students/?search=e  # 支持模糊匹配
2.2、第三方扩展的过滤功能
# 对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持
pip install django-filter  # 最新版本(2.4.0)要跟django2.2以上搭配
from django_filters.rest_framework import DjangoFilterBackend

# 在配置文件中增加过滤后端的设置
INSTALLED_APPS = [
    ...
    'django_filters',  # 需要注册应用
]
# 全局配置
REST_FRAMEWORK = {
    ...
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

# 在视图中添加filter_fields属性,指定可以过滤的字段
class StudentListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
	# 类视图配置
	filter_backends = [DjangoFilterBackend, ]
    filter_fields = ['id', 'gender', 'name']

查询的时候
# http://127.0.0.1:8000/stu/?gender=1
2.3、排序
对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序

使用方法:
在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。

前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明

class StudentListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_backends = [OrderingFilter]
    ordering_fields = ('id', 'age')

# 127.0.0.1:8000/books/?ordering=-age
# -id 表示针对id字段进行倒序排序
# id  表示针对id字段进行升序排序
如果需要在过滤以后再次进行排序,则需要两者结合

from rest_framework.generics import ListAPIView
from students.models import Student
from .serializers import StudentModelSerializer
from django_filters.rest_framework import DjangoFilterBackend
class Student3ListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_fields = ('age', 'gender')
    # 因为局部配置会覆盖全局配置,所以需要重新把过滤组件核心类再次声明,
    # 否则过滤功能会失效
    filter_backends = [OrderingFilter,DjangoFilterBackend]
    ordering_fields = ('id', 'age')

3、分页Pagination

REST framework提供了分页的支持
我们可以在配置文件中设置全局的分页方式,如:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100  # 每页数目
}

可通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas属性来指明

class LargeResultsSetPagination(PageNumberPagination):
    page_size = 1000
    page_size_query_param = 'page_size'
    max_page_size = 10000
    
class BookDetailView(RetrieveAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    pagination_class = LargeResultsSetPagination

注意:如果在视图内关闭分页功能,只需在视图内设置

pagination_class = None
3.1、可选分页器
3.1.1、PageNumberPagination

前端访问网址形式

GET  http://127.0.0.1:8000/students/?page=4

可以在子类中定义的属性:

  • page_size 每页数目
  • page_query_param 前端发送的页数关键字名,默认为”page”
  • page_size_query_param 前端发送的每页数目关键字名,默认为None
  • max_page_size 前端最多能设置的每页数量
# APIView
from rest_framework.pagination import PageNumberPagination
# 一 基本使用: url=url=http://127.0.0.1:8000/pager/?page=2&size=3,size无效
class  Pager(APIView):
    def get(self,request,*args,**kwargs):
        # 获取所有数据
        ret=models.Book.objects.all()
        # 创建分页对象
        page=PageNumberPagination()
        # 在数据库中获取分页的数据
        page_list=page.paginate_queryset(ret,request,view=self)
        # 对分页进行序列化
        ser=BookSerializer1(instance=page_list,many=True)
        return Response(ser.data)
        
# 二 自定制: url=http://127.0.0.1:8000/pager/?page=2&size=3
# size=30,无效,最多5条
class Mypage(PageNumberPagination):
    page_size = 2
    page_query_param = 'page'
    # 定制传参
    page_size_query_param = 'size'
    # 最大一页的数据
    max_page_size = 5
    
class  Pager(APIView):
    def get(self,request,*args,**kwargs):
        # 获取所有数据
        ret=models.Book.objects.all()
        # 创建分页对象
        page=Mypage()
        # 在数据库中获取分页的数据
        page_list=page.paginate_queryset(ret,request,view=self)
        # 对分页进行序列化
        ser=BookSerializer1(instance=page_list,many=True)
        # return Response(ser.data)
        # 这个也是返回Response对象,但是比基本的多了上一页,下一页,和总数据条数(了解即可)
        return page.get_paginated_response(ser.data)
      
#ListAPIView
# 声明分页的配置类
from rest_framework.pagination import PageNumberPagination
class StandardPageNumberPagination(PageNumberPagination):
    # 默认每一页显示的数据量
    page_size = 2
    # 允许客户端通过get参数来控制每一页的数据量
    page_size_query_param = "size"
    max_page_size = 10
    # 自定义页码的参数名
    page_query_param = "p"

class StudentAPIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    pagination_class = StandardPageNumberPagination

# 127.0.0.1/four/students/?p=1&size=5
3.1.2、LimitOffsetPagination

前端访问网址形式

GET http://127.0.0.1/four/students/?limit=100&offset=400

可以在子类中定义的属性:

  • default_limit 默认限制,默认值与PAGE_SIZE设置一直
  • limit_query_param limit参数名,默认’limit’
  • offset_query_param offset参数名,默认’offset’
  • max_limit 最大limit限制,默认None
# APIView
# http://127.0.0.1:8000/pager/?offset=4&limit=3
from rest_framework.pagination import LimitOffsetPagination
# 也可以自定制,同简单分页
class  Pager(APIView):
    def get(self,request,*args,**kwargs):
        # 获取所有数据
        ret=models.Book.objects.all()
        # 创建分页对象
        page=LimitOffsetPagination()
        # 在数据库中获取分页的数据
        page_list=page.paginate_queryset(ret,request,view=self)
        # 对分页进行序列化
        ser=BookSerializer1(instance=page_list,many=True)
        # return page.get_paginated_response(ser.data)
        return Response(ser.data)
        
#ListAPIView
from rest_framework.pagination import LimitOffsetPagination
class StandardLimitOffsetPagination(LimitOffsetPagination):
    # 默认每一页查询的数据量,类似上面的page_size
    default_limit = 2
    limit_query_param = "size"
    offset_query_param = "start"

class StudentAPIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    # 调用页码分页类
    # pagination_class = StandardPageNumberPagination
    # 调用查询偏移分页类
    pagination_class = StandardLimitOffsetPagination
3.1.3、CursorPagination

前端访问网址形式

GET http://127.0.0.1/four/students/?cursor=cD0xNQ%3D%3D

可以在子类中定义的属性:

  • cursor_query_param:默认查询字段,不需要修改
  • page_size:每页数目
  • ordering:按什么排序,需要指定
#APIView
from rest_framework.pagination import CursorPagination
# 看源码,是通过sql查询,大于id和小于id
class  Pager(APIView):
    def get(self,request,*args,**kwargs):
        # 获取所有数据
        ret=models.Book.objects.all()
        # 创建分页对象
        page=CursorPagination()
        page.ordering='nid'
        # 在数据库中获取分页的数据
        page_list=page.paginate_queryset(ret,request,view=self)
        # 对分页进行序列化
        ser=BookSerializer1(instance=page_list,many=True)
        # 可以避免页码被猜到
        return page.get_paginated_response(ser.data)
        
# ListAPIView
class MyCursorPagination(CursorPagination):
    page_size=2
    ordering='-id'
    
from rest_framework.generics import ListAPIView
class AuthorListView(ListAPIView):
    serializer_class = serializers.AuthorModelSerializer
    queryset = models.Author.objects.filter(is_delete=False)
    pagination_class =MyCursorPagination
3.1.4、应用
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
class MyPageNumberPagination(PageNumberPagination):
    page_size = 2
    page_query_param = 'page'
    # 定制传参
    page_size_query_param = 'size'
    # 最大一页的数据
    max_page_size = 5

class MyLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 2
    # 最大一页的数据
    max_limit = 5
    
class MyCursorPagination(CursorPagination):
    page_size=2
    ordering='-id'
    
from rest_framework.generics import ListAPIView
class AuthorListView(ListAPIView):
    serializer_class = serializers.AuthorModelSerializer
    queryset = models.Author.objects.filter(is_delete=False)
    pagination_class =MyCursorPagination
3.2、三种分页的使用总结
1、内置了三种分页器
	PageNumberPagination: 普通分页
    LimitOffsetPagination: 偏移分页
    CursorPagination: 游标分页
    
2、APIView和GenericAPIView+ListModelMixin
3、GenericAPIView+ListModelMixin的分页模式
	
4、PageNumberPagination: 普通分页(使用频率最多)
	page_size = api_settings.PAGE_SIZE  # 每页显示多少条
    page_query_param = 'page'           # 查询参数
    page_size_query_param = size        # 查询的时候指定每页显示多少条
    max_page_size = 10                  # 每页最多显示多少条
    
    使用方式:
    	定义一个类,继承PageNumberPagination
        重写四个属性
        在继承了GenericAPIView+ListModelMixin视图类中配置
        	pagination_class = MyPageNumberPagination
        查询
        	http://127.0.0.1:8000/students/?page=1&size=5
            
5、LimitOffsetPagination: 偏移分页
    default_limit = api_settings.PAGE_SIZE  # 默认条数
    limit_query_param = 'limit'             # 查询时,指定查询多少条
    offset_query_param = 'offset'           # 查询时,指定的起始位置是哪 
    max_limit = None                        # 查询时,最多返回多少条
    使用方式:
    	定义一个类,继承LimitOffsetPagination
        重写四个属性
        在继承了GenericAPIView+ListModelMixin视图类中配置
        	pagination_class = MyPageNumberPagination
        查询
        http://127.0.0.1:8000/students/?limit=100&offset=1
        
6、CursorPagination: 游标分页(速度块)
	cursor_query_param = 'cursor'       # 查询的时候,指定的查询方式
    page_size = api_settings.PAGE_SIZE  # 每页显示多少条
    ordering = '-created'               # 排序方式
    page_size_query_param = size        # 查询的时候指定每页显示多少条
    max_page_size = None                # 每页最多显示多少条
    使用方式:
            定义一个类,继承CursorPagination
            重写四个属性
            在继承了GenericAPIView+ListModelMixin视图类中配置
                pagination_class = MyPageNumberPagination
            查询
            http://127.0.0.1:8000/students/?cursor=cD0xNQ%3D%3D               
                    
 7、APIView的分页模式
	新建一个类,继承普通分页,重写四个属性
    视图类写法如下:
	class StudentApiView(APIView):
        def get(self,request):
            student_list=Student.objects.all()
            page=MyPageNumberPagination()  # 实例化得到对象
            # 只需要换不同的分页类即可
            res=page.paginate_queryset(student_list,request,self)  # 开始分页
            ser=StudentSerializer(res,many=True)
            return page.get_paginated_response(ser.data) # 返回数据
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值