6.三大认证等

【一】三大认证

# 认证
self.perform_authentication(request)
# 权限
self.check_permissions(request)
# 频率
self.check_throttles(request)

【二】认证

1)使用

  • 新建一个py文件(authentication.py)

  • 写一个类继承BaseAuthentication

  • 重写authenticate函数

    from rest_framework.authentication import BaseAuthentication
    from rest_framework.exceptions import AuthenticationFailed
    from App.models import Token
    
    class LoginAuthentication(BaseAuthentication):
        def authenticate(self, request):
            # 取出请求头中的token数据
            token = request.META.get('HTTP_TOKEN')
            # 校验登录token是否有效
            user_token = Token.objects.filter(token=token).first()
            if user_token:
                # 返回用户,token
                return user_token.user, token
            else:
                # 主动抛异常
                raise AuthenticationFailed('请先登录')
    
  • 将认证类配置到视图类内

    # 局部配置
    authentication_classes = [LoginAuthentication]
    # 全局配置
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'App.base.authentication.LoginAuthentication'
        ]
    }
    

【三】权限

1)使用

  • 新建一个py文件(permissions.py

  • 写一个类继承BasePermission

  • 重写has_permission函数

    from rest_framework.permissions import BasePermission
    
    class CommonPermission(BasePermission):
        def has_permission(self, request, view):
            # view.action:请求状态
            if view.action == 'list' or view.action == 'retrieve':
                return True
            else:
                limit = request.user.limit
                if limit == 1:
                    return True
                else:
                    self.message = f'当前为【{request.user.get_limit_display()}】登录,权限不足'
                    return False
    
  • 将认证类配置到视图类内

    # 局部配置
    permission_classes = [CommonPermission]
    # 全局配置
    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': [
            'App.base.permissions.CommonPermission'
        ]
    }
    

【四】频率

1)使用

  • 新建一个py文件(throttles.py

  • 写一个类继承SimpleRateThrottle

  • 设置频率

    # 支持的时间:s,m,h,d
    # 每分钟3次
    rate = '3/m'	
    
  • 重写get_cache_key函数

    # SimpleRateThrottle 内继承了 BaseThrottle
    from rest_framework.throttling import SimpleRateThrottle
    
    class CommonThrottle(SimpleRateThrottle):
        # 设置频率(每分钟3次)(s,m,h,d)
        rate = '3/m'
    
        def get_cache_key(self, request, view):
            print(request.META)
            # 以返回的内容作为限制
            ip = request.META.get('REMOTE_ADDR')
            return ip
    
  • 将认证类配置到视图类内

    # 局部配置
    throttle_classes = [CommonThrottle]
    # 全局配置
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_RATES':[
            'App.base.throttling.CommonThrottle'
        ]
    }
    

【五】排序,过滤

1)排序

  • 引入

    from rest_framework.filters import OrderingFilter
    
  • 添加到视图类内

    # 排序
    # 需注册排序依据,才能使用
    # http://localhost:8000/api/v1/book/?ordering=price,-id
    # 哪个依据在前,就先按照那个排序
    filter_backends = [OrderingFilter]
    ordering_fields = ['price', 'id']
    

2)过滤

1.方式一:drf内置方法,只能使用search进行模糊查询

  • 引入

    from rest_framework.filters import SearchFilter
    
  • 添加到视图类内

    # 需注册排序依据,才能使用
    # http://localhost:8000/api/v1/book/?search=书
    filter_backends = [SearchFilter]
    search_fields = ['name']
    

2.方式二:第三方django_filter,只能精确查询

  • 引入

    from django_filters.rest_framework.backends import DjangoFilterBackend
    
  • 添加到视图类内

    # 需注册排序依据,才能使用
    # http://localhost:8000/api/v1/book/?name=书1&price=80
    filter_backends = [ DjangoFilterBackend]
    filterset_fields = ['name','price']
    

3.方式三:自定义过滤

  • 新建一个py文件(filters.py

  • 写一个类继承BaseFilterBackend

  • 重写filter_queryset函数

    __contains:模糊查询
    __gt:大于查询
    __lt:小于查询
    __gte:大于等于查询
    __lte:小于等于查询
    
    from django.db.models import Q
    from rest_framework.filters import BaseFilterBackend
    
    
    class CommonFilterBackend(BaseFilterBackend):
        def filter_queryset(self, request, queryset, view):
            name = request.query_params.get('name')
            price = request.query_params.get('price')
            price_gt = request.query_params.get('price_gt')
            price_lt = request.query_params.get('price_lt')
            if name and price_gt and price_lt:
                queryset = queryset.filter(name__contains=name, price__gt=price_gt, price__lt=price_lt)
            elif price_gt and price_lt:
                queryset = queryset.filter(price__gt=price_gt, price__lt=price_lt)
            elif name and price:
                queryset = queryset.filter(Q(name__contains=name) | Q(price=price))	# 或关系
            elif name:
                # 模糊查询
                queryset = queryset.filter(name__contains=name)
            elif price:
                # 精确查询
                queryset = queryset.filter(price=price)
            return queryset
    
  • 将认证类配置到视图类内

    # 局部配置
    filter_backends = [CommonFilterBackend]
    # 全局配置
    REST_FRAMEWORK = {
        'DEFAULT_FILTER_BACKENDS': [
             'App.base.filters.CommonFilterBackend'
         ]
    }
    
  • 使用

    http://localhost:8000/api/v1/book/?name=书&price=30
    

【六】分页

  • 新建一个py文件(pagination.py

  • 写一个类继承PageNumberPagination

  • 定义函数

    from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
    
    # 基本分页
    class CommonPagination(PageNumberPagination):
        # 默认一页显示的数量
        page_size = 2
        # 指定页数的key
        # http://localhost:8000/api/v1/book/
        # http://localhost:8000/api/v1/book/?p=2
        page_query_param = 'page'
        # 指定显示的数量的key
        # http://localhost:8000/api/v1/book/?s=3
        page_size_query_param = 'size'
        # 每页最大显示数量
        max_page_size = 5
       
    # 可指定每页的数据
    class CommonLimitOffsetPagination(LimitOffsetPagination):
        # 默认一页显示的数量
        default_limit = 2
        # 指定页数的key
        limit_query_param = 'limit'
        # 偏移量的key
        offset_query_param = 'offset'
        # 每页最大显示数量
        max_limit = 5
        # http://localhost:8000/api/v1/book/
        # http://localhost:8000/api/v1/book/?limit=2&offset=2
      
    # 无法预测每页的参数,
    class CommonCursorPagination(CursorPagination):
        # 默认一页显示的数量
        page_size = 2
        # 指定页数的key
        cursor_query_param = 'cursor'
        # 排序依据的字段
        ordering = 'id'
    
  • 将认证类配置到视图类内

    # 局部配置
    pagination_class = CommonPagination
    

【七】全局异常

1)3大类异常

  • drf的异常
  • django的异常
  • python的异常

2)使用

  • 新建一个py文件(abnormity.py

  • 引入

    from rest_framework.views import exception_handler
    
  • 定义函数

    def common_exception_handler(exc, context):
        # 日志记录
        request = context.get('request')
        view = context.get('view')
        print(f'时间:{time.time()},'
              f'用户:{request.user.username or "未知用户"},'
              f'访问地址:{request.get_full_path()},'
              f'请求方式:{request.method},'
              f'视图类:{str(view)}')
        # -----------------
        # 异常错误处理,统一返回格式
        response = exception_handler(exc, context)
        # drf的异常返回对象,其余返回None
        if response:
            if isinstance(response.data, dict):
                msg = response.data.get("detail") or '未知错误'
            elif isinstance(response.data, list):
                msg = response.data[0]
            return Response({'code': 100, 'msg': msg})
        else:
            return Response({'code': 100, 'msg': str(exc)})
    
  • 将认证类配置到视图类内

    # 使用全局配置
    REST_FRAMEWORK = {
        'EXCEPTION_HANDLER': 'App.base.exception.common_exception_handler'
    }
    
posted on 2024-08-01 10:40  晓雾-Mist  阅读(1)  评论(0编辑  收藏  举报