DRF中的限流是指对API接口访问的频次进行限制,以减轻服务器压力,以防止恶意用户或者其他原因导致的API滥用。
Throttling可以根据用户的IP地址、用户名或者其他自定义的标识符来限制其访问API的频率。
DRF中提供了多种内置的限流类,可以根据不同的需求选择合适的限流方式。
常用的限流类:
类 | 说明 |
---|---|
AnonRateThrottle | 根据匿名用户的IP地址进行限流。适合希望限制未知来源的请求率 |
UserRateThrottle | 根据已认证用户的ID进行限流。适合希望对每个用户进行简单的全局速率限制 |
ScopedRateThrottle | 用于限制对 API 特定部分的访问,如视图的访问,根据用户IP或用户ID进行限流。 |
DRF框架默认没有进行全局限流设置,可以在配置文件中,使用
DEFAULT_THROTTLE_CLASSES
和DEFAULT_THROTTLE_RATES
进行设置全局的默认限流策略。
1.针对匿名用户和认证用户分别进行限流控制
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
# 基本认证
'rest_framework.authentication.BasicAuthentication',
# sesssion认证
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
# 将全局权限控制方案设置为仅允许认证用户访问
'rest_framework.permissions.IsAuthenticated',
),
# 限流控制
'DEFAULT_THROTTLE_CLASSES': (
# 针对未登录(匿名)用户的限流控制类
'rest_framework.throttling.AnonRateThrottle',
# 针对登录(认证)用户的限流控制类
'rest_framework.throttling.UserRateThrottle'
),
# 指定限流频次
'DEFAULT_THROTTLE_RATES': {
# 认证用户的限流频次,一分钟内超过3此访问则出发限流
'user': '3/minute',
# 匿名用户的限流频次,一秒内超过3此访问则出发限流
'anon': '3/second',
},
}
DEFAULT_THROTTLE_RATES
中使用的频率描述可选限流周期单位包括:second、minute、hour、day
2.针对匿名用户和认证用户进行统一的限流控制
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.ScopedRateThrottle',
),
在每个视图或每个视图集的基础上设置限流策略,通过throttle_classess
属性配置限流控制类。
class TestView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
throttle_classes = [AnonRateThrottle]
可以根据实际需求定义自己的限流频次选择项
# 指定限流频次选择项
'DEFAULT_THROTTLE_RATES': {
'a': '3/minute',
'b': '2/minute'
},
使用
class TestView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# 针对匿名用户和认证用户进行统一的限流控制
throttle_classes = [ScopedRateThrottle]
# 指定限流频次项
throttle_scope = 'a'
要自定义限流,需要创建一个继承自 BaseThrottle类的子类,并实现其中的
allow_request
和wait
方法。
allow_request
方法用于判断是否允许请求通过,它接收两个参数:请求对象和视图对象。如果返回True,则说明请求被允许通过;否则返回 False,表示请求被拒绝。
wait
方法用于计算下一次请求可通过的时间,它接收三个参数:请求对象、视图对象和当前已发生的请求次数。如果返回 None,则说明请求可以立即通过;否则返回一个时间戳,表示下一次请求可通过的时间。
自定义简单限流示例:
from rest_framework.throttling import BaseThrottle
class MyCustomThrottle(BaseThrottle):
def allow_request(self, request, view):
# 在这里编写判断逻辑,返回 True 或 False
return True
def wait(self, request, view, num_requests):
# 在这里编写等待逻辑,返回 None 或下一次请求可通过的时间戳
return None
class TestView(ModelViewSet):
queryset = User.objects.all().filter(name='Java')
serializer_class = UserSerializer
class TestView(ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
@action(methods=['get'], detail=False)
def myFun(self, request):
query_param = request.query_params.get('name', None)
data = self.queryset.filter(name=query_param)
newData = list(data.values()) # 将查询集转换为列表
return JsonResponse(newData, safe=False) # 将数据转换为JSON格式并返回
访问:http://127.0.0.1:8000//test/myFun/?name=Vue
Django REST framework (DRF) 提供了许多过滤器组件,用于在视图中进行过滤和排序。这些过滤器组件可以轻松地与 Django ORM 进行集成,并对查询结果进行筛选、排序和限制。
常见过滤器组件
1.DjangoFilterBackend
允许使用 Django Filter 库中的过滤器来进行高级查询。通过在视图类中设置 filter_fields 属性来指定可用的过滤字段。
2.SearchFilter
允许用户基于搜索关键字来查找特定的数据。可以通过在视图类中设置 search_fields 属性来指定可用于搜索的字段。
3.OrderingFilter:
允许用户根据选择的字段进行排序。可以通过在视图类中设置 ordering_fields 属性来指定可用于排序的字段。
4.LimitOffsetPagination:
允许将大型数据集分页显示,并允许用户针对每个页面请求特定数量的条目。
5.PageNumberPagination
与 LimitOffsetPagination 类似,但是更加常用,因为它支持按页码进行操作。
django-filter库包含一个为REST framework提供高度可定制字段过滤的DjangoFilterBackend类,通过添加django-fitlter扩展来增强支持。
安装django-filter
pip install django-filter
在项目settings.py文件中注册应用:
INSTALLED_APPS = [
'django_filters',
]
1.全局使用
在settings.py文件中增加过滤后端的配置:
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter')
}
2.局部使用
在视图函数或视图集中指定相应的过滤器类和过滤器后端
from rest_framework.filters import OrderingFilter
class TestView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# 指定排序类
filter_backends = [OrderingFilter]
# 指定排序字段
ordering_fields = ('id','name')
在视图类属性filter_backends中指定要使用的过滤器类
在视图中添加filter_fields属性,指定可以过滤的字段
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.viewsets import ModelViewSet
from user.models import User
from user.serializers import UserSerializer
class TestView(ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
# filter_backends = [DjangoFilterBackend]
filterset_fields = ("name", "age")
访问:http://127.0.0.1:8000/test/
访问: http://127.0.0.1:8000/test/?age=30
访问: http://127.0.0.1:8000/test/?age=20&name=Java
DRF提供了OrderingFilter过滤器来帮助快速指明数据按照指定字段进行排序。
DRF会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。
from rest_framework.filters import OrderingFilter
class TestView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# 指定排序类
filter_backends = [OrderingFilter]
# 指定排序字段
ordering_fields = ('id','name')
访问:http://127.0.0.1:8000/test/?ordering=id
访问: http://127.0.0.1:8000/test/?ordering=name
在DRF中,分页类是用于处理 API 响应数据分页的工具类。DRF 提供了多个分页类可以选择使用,其中最常用的分页类为
PageNumberPagination
和LimitOffsetPagination
。
如果在视图内关闭分页功能,只需在视图内设置:
pagination_class = None
1.PageNumberPagination
PageNumberPagination
是基于页码来进行分页的分页类,它根据请求参数中传递的页码和每页显示的数量来返回相应的结果。
访问URL形式: http://127.0.0.1:8000/test/?page=2
可以在子类中定义的属性:
属性 | 说明 |
---|---|
page_size | 每页数目 |
page_query_param | 请求发送的页数关键字名,默认为"page" |
page_size_query_param | 请求发送的每页数目关键字名,默认为None |
max_page_size | 请求最多能设置的每页数量 |
2.LimitOffsetPagination
LimitOffsetPagination
是基于偏移量和限制条目数来进行分页的分页类,它根据请求参数中传递的偏移量和限制条目数来返回相应的结果。
访问UR形式:http://127.0.0.1:8000/test/?limit=1&offset=2
可以在子类中定义的属性:
属性 | 说明 |
---|---|
default_limit | 默认限制,默认值与PAGE_SIZE设置一直 |
limit_query_param limit | 参数名,默认’limit’ |
offset_query_param offset | 参数名,默认’offset’ |
max_limit | 最大limit限制,默认None |
在配置文件中设置全局分页方式,或者在视图类中设置
pagination_class
属性,并指定需要使用的分页类
1.全局
REST_FRAMEWORK = {
# 指定使用的分页类
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 2 # 每页数量
}
访问: http://127.0.0.1:8000/test/?page=2
2.局部
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
class TestView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
pagination_class = PageNumberPagination
pagination_class = LimitOffsetPagination
通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas属性来指明。
from rest_framework.pagination import PageNumberPagination
from rest_framework.viewsets import ModelViewSet
from user.models import User
from user.serializers import UserSerializer
class MyPagination(PageNumberPagination):
page_size = 2
page_size_query_param = 'page_size'
class TestView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# 指定当前视图所使用的分页类
pagination_class = MyPagination
访问: http://127.0.0.1:8000/test/?page_size=3
from rest_framework.pagination import LimitOffsetPagination
class MyPagination(LimitOffsetPagination):
default_limit = 1
max_limit = 2
class TestView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# 指定当前视图所使用的分页类
pagination_class = MyPagination
访问:http://127.0.0.1:8000//test/?limit=2&offset=2
在DRF中,异常处理是通过在视图函数中捕获异常来完成的。当出现异常时,将生成一个标准响应,其中包含有关异常的详细信息。
DRF提供了异常处理,常见的DRF异常类如下:
异常类 | 描述 |
---|---|
APIException | 所有异常的父类 |
ValidationError | 当验证失败时引发的异常 |
ParseError | 当无法解析请求体时引发的异常 |
AuthenticationFailed | 当身份验证失败时引发的异常 |
NotAuthenticated | 尚未认证引发的异常 |
PermissionDenied | 当用户权限不足时引发的异常 |
NotFound | 当未找到资源时引发的异常 |
MethodNotAllowed | 当尝试使用不支持的HTTP方法或操作时引发的异常 |
UnsupportedMediaType | 当请求使用了不受支持的媒体类型时引发的异常 |
NotAcceptable | 要获取的数据格式不支持引发的异常 |
Throttled | 超过限流次数引发的异常 |
DRF框架默认使用
rest_framework.views.exception_handler
模块下的exception_handler
函数进行异常处理。
默认异常处理设置:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
可以通过定义自己的异常类来扩展这些异常,并在视图函数中捕获和处理它们。要定义自己的异常类,请从DRF中的APIException类继承,并设置status_code属性和default_detail属性
from rest_framework.exceptions import APIException
class MyException(APIException):
status_code = 400
default_detail = '自定义异常信息'
在视图函数中,您可以使用try/except块来捕获异常并返回相应的响应:
class TestView(APIView):
def get(self, request):
try:
print("do something")
1/0
except ZeroDivisionError as e:
raise MyException()
return Response({'msg': "OK"}, status=200)
urlpatterns = [
re_path(r'test/', views.TestView.as_view(), name='test'),
]
DRF框架提供了很多异常处理函数,但有时候我们可能需要补充一些其他的异常信息处理。因此,可以在DRF框架异常处理函数的基础上,进行异常信息的增强。
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.views import exception_handler as drf_exception_handler
def exception_handler(exc, context):
# 先调用DRF框架的默认异常处理函数
response = drf_exception_handler(exc, context)
if response is None:
view = context['view']
# 补充异常处理
if isinstance(exc, ZeroDivisionError):
print('[%s]: %s' % (view, type(exc)))
response = Response({'msg': '除数不能为零'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return response
class TestView(APIView):
def get(self, request):
1 / 0
return Response({'msg': "OK"}, status=200)
在配置文件中声明自定义的异常处理:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'user.utils.exceptions.exception_handler'
}