DRF权限频率过滤异常处理

DRF权限频率过滤异常处理

1 权限

1.1 权限源码的分析

# APIView---->dispatch---->initial--->self.check_permissions(request)(APIView的对象方法)
    def check_permissions(self, request):
        # 遍历权限对象列表得到一个个权限对象(权限器),进行权限认证
        for permission in self.get_permissions():
            # 权限类一定有一个has_permission权限方法,用来做权限认证的
            # 参数:权限对象self、请求对象request、视图类对象
            # 返回值:有权限返回True,无权限返回False
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request, message=getattr(permission, 'message', None)
                )

1.2 自定义权限

from rest_framework.permissions import BasePermission


# 自定义权限
class UserPermission(BasePermission):
    def has_permission(self, request, view):
        if request.user.types == 0:   # 0为超级用户,直接返回True
            return True
        elif request.user.types == 1: # 1为会员用户,只具有'GET'和'POST'的权限
            return request.method in ['GET', 'POST']
        elif request.user.types == 2: # 2为普通用户,只具有‘GET’权限
            return request.method == 'GET'
        else:
            return False

局部使用:

from app01.utils.auth_check import LogAuthentication
class LoginView(APIView):
    # 自定义方法
    authentication_classes = []
    permission_classes = [LogAuthentication,]

    def post(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user = User.objects.filter(username=username, password=password).first()
        if user:
            token = ''.join(str(uuid4()).split('-')).upper()
            token_obj = APIToken.objects.update_or_create(defaults={'token': token}, user=user)
            return APIResponse(data={'token': token})
        else:
            return APIResponse(code='103', msg='用户不存在')

全局使用

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [  # 权限的全局配置
        # 'app01.utils.permission.UserPermission', # 自定义的权限配置
        'rest_framework.permissions.IsAdminUser',  # 使用内置的权限配置
    ],
}

局部禁用

class LoginView(APIView):
    # 自定义方法
    authentication_classes = []
    permission_classes = []

1.3 内置权限的使用(了解)

class Login2View(APIView):
    # 内置的方法
    authentication_classes = []
    permission_classes = []

    def post(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user = auth.authenticate(username=username, password=password)
        if user:
            auth.login(request, user)
            return APIResponse(msg='登录成功', data={'user': request.user.username})
        else:
            return APIResponse(code='103', msg='用户不存在')

2 过滤&排序

2.1 过滤

安装第三方模块django-filter,注意django的版本需要在 2.2以及之上

pip install django-filter

查看django的版本

>>> import django
>>> print(django.VERSION)
(2, 2, 14, 'final', 0)

局部使用

from django-filter.rest_framework import DjangoFilterBackend

from rest_framework.generics import ListAPIView
class Book3View(ListAPIView):
    queryset = Book.objects.all()
    serializer_class = GETSerializer
    filter_backends = (DjangoFilterBackend,OrderingFilter)
    filter_fields = ['name'] # 参与过滤的字段
    ordering_fields = ('id','price') # 参与排序的字段

全局使用

# 在app中进行注册
INSTALLED_APPS = [
    'rest_framework',
    'django-filter', #针对浏览器
]

# REST_FRAMEWORK = {
	'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

# Views.py
class BookView(ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_fields = ('name',)  #配置可以按照哪个字段来过滤

2.2 排序

# 局部使用
from rest_framework.filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend

from rest_framework.generics import ListAPIView
class Book3View(ListAPIView):
    queryset = Book.objects.all()
    serializer_class = GETSerializer
    filter_backends = (DjangoFilterBackend,OrderingFilter)
    filter_fields = ['name'] # 参与过滤的字段
    ordering_fields = ('id','price') # 参与排序的字段
    
# 全局配置
REST_FRAMEWORK = {
	'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend','rest_framework.filters.OrderingFilter',)
}

3 频率

3.1 内置频率的限制(限制未登录的用户)

# 全局使用  限制未登录用户1分钟访问5次
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '3/m',
    }
}
##############views.py
from rest_framework.permissions import IsAdminUser
from rest_framework.authentication import SessionAuthentication,BasicAuthentication
class TestView4(APIView):
    authentication_classes=[]
    permission_classes = []
    def get(self,request,*args,**kwargs):
        return Response('我是未登录用户')

# 局部使用
from rest_framework.permissions import IsAdminUser
from rest_framework.authentication import SessionAuthentication,BasicAuthentication
from rest_framework.throttling import AnonRateThrottle
class TestView5(APIView):
    authentication_classes=[]
    permission_classes = []
    throttle_classes = [AnonRateThrottle]
    def get(self,request,*args,**kwargs):
        return Response('我是未登录用户,TestView5')

3.2 内置频率(限制用户访问的次数)

# 需求:未登录用户1分钟访问5次,登录用户一分钟访问10次
全局:在setting中
  'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'user': '10/m',
        'anon': '5/m',
    }
        
 局部配置:
	在视图类中配一个就行

4 异常处理

from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status


def api_exception_handler(exc, context):
    response = exception_handler(exc, context)
    # 一种是None,drf没有处理
    # 另外一种是Response对象(Django处理的),但是不符合我们的要求
    # print(type(exc))

    if not response:
        if isinstance(exc, ZeroDivisionError):
            return Response(data={'status': 777, 'msg': "除以0的错误" + str(exc)}, status=status.HTTP_400_BAD_REQUEST)
        return Response(data={'status': 999, 'msg': str(exc)}, status=status.HTTP_400_BAD_REQUEST)
    else:
        # return response
        return Response(data={'status': 888, 'msg': response.data.get('detail')}, status=status.HTTP_400_BAD_REQUEST)

5 封装Response

# 以后都用自己封装的
class APIResponse(Response):
    def __init__(self,code=100,msg='成功',data=None,status=None,headers=None,**kwargs):
        dic = {'code': code, 'msg': msg}
        if  data:
            dic = {'code': code, 'msg': msg,'data':data}
        dic.update(kwargs)
        super().__init__(data=dic, status=status,headers=headers)
# 使用
return APIResponse(data={"name":'lqz'},token='dsafsdfa',aa='dsafdsafasfdee')
return APIResponse(data={"name":'lqz'})
return APIResponse(code='101',msg='错误',data={"name":'lqz'},token='dsafsdfa',aa='dsafdsafasfdee',header={})
原文地址:https://www.cnblogs.com/surpass123/p/13285451.html