2020-12-14 drf--分页、全局异常捕获、接口文档

回顾

1、编写登录接口,图书5大接口,实现图书5大接口匿名用户一分钟访问3次,登录用户一分钟访问10次

-方式一:
    -写两个频率类(一个是根据IP限制,零以恶个是根据user id限制)
-方式2:
    -使用内置的,如果可以,就没问题,如果有问题就要继续重写get_cache_key方法

2、一个接口即可以不登陆访问,又可以登录访问(匿名用户一分钟访问3次,登录用户一分钟访问10次)

-认证类:额外写
    class LoginAuth(BaseAuthentication):
        def authenticate(self, request):
            #写认证规则,如果认证通过,就正常return
            #如果认证失败,抛异常
            # 取出携带的随机字符串,去数据判断,如果有,正常登录,没有,告诉它没有登录
            #token可以放在get请求的参数中,也可以放请求头中
            token=request.GET.get('token')

            res=models.UserToken.objects.filter(token=token).first()
            if res:
                return (res.user,token)
            else:
                return None  # 由于是登录喝未登录都可以访问一个接口,所以未登录就返回个None,这样就不会报错,就正常走到下面的限制了

-未登录用户的频率限制
    class MySimpleThrottleauth(SimpleRateThrottle):
        scope = 'xxx'
        def get_cache_key(self, request, view):
            if not request.user.id:  # 没有登录用户
                return self.get_ident(request) # 根据ip限制
            else:
                return None  # 登录用户则啥也不管,就会到下一个频率限制

-登录用户的频率限制,根据用户id限制
    class MyLoginThrottle(SimpleRateThrottle):
        scope = 'login'
        def get_cache_key(self, request, view):
            return request.user.pk

3、排序(内置排序规则)

-在视图类中配置
    filter_backends =[OrderingFilter,]
    ordering_fields=['id','age']
-查询:
    http://127.0.0.1:8000/students/?ordering=-age

4、过滤(内置)

-在视图类中配置
    filter_backends =[SearchFilter,]
    search_fields=('name','age')
-查询:
    http://127.0.0.1:8000/students/?search=9,l

5、过滤(django-filter)

    -在视图类中配置
        filter_backends =[DjangoFilterBackend,]
        filter_fields=['name','age']
    -查询:
        http://127.0.0.1:8000/students/?name=lqz&age=10

#自定义过滤器
    -查询所有才会有过滤---》list才需要过滤---》queryset = self.filter_queryset(self.get_queryset())---》GenericAPIView-->filter_queryset
    #重写这个方法
    def filter_queryset(self, queryset):
            for backend in list(self.filter_backends):
                queryset = backend().filter_queryset(self.request, queryset, self)
            return queryset
基于django-filter扩写也可以,但是要熟悉它的源码

可以继承内置筛选器类来扩写
-1、写一个类MyFilter,继承BaseFilterBackend
-2、重写filter_queryset方法,在该方法内部进行过滤,(自己 设置的过滤条件)
-3、返回queryset对象(过滤后的queryset对象)
-4、配置在视图类中
    filter_backends = [MyFilter,]

例子

#自定义过滤器,名字以l开头的人
from rest_framework.filters import BaseFilterBackend
class MyFilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        #name=startswith_l  名字以l开头的人
        value=request.GET.get('name')
        first,last=value.split('_')
        if first=='startswith':
            queryset=queryset.filter(name__startswith=last)
        return queryset

今日内容

1 分页器(三种)重点如何使用

-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          #每页最多显示多少条,一般不去改,不太用
    -使用方式:
            -定义一个类,继承LimitOffsetPagination
            -重写四个属性
            -在继承了GenericAPIView+ListModelMixin视图类中配置
                pagination_class = MyPageNumberPagination
            -查询,直接在页面上点链接,查看上一页下一页,不能选择跳转自定义页面
            http://127.0.0.1:8000/students/

-7、APIView的分页模式
    -新建一个类,继承普通分页,重写四个属性
    -视图类写法如下
    class StudentApiView(APIView):
        def get(self,request):
            student_list=Student.objects.all()
            # page=MyCursorPagination()
            # page=MyLimitOffsetPagination()
            page=MyPageNumberPagination()# 实例化得到对象
            # 只需要换不同的分页类即可
            res=page.paginate_queryset(student_list,request,self)# 开始分页
            ser=StudentSerializer(res,many=True)   # 将分页好的数据传入序列化器
            return page.get_paginated_response(ser.data) # 返回数据

2、全局异常

-1、统一接口的返回方式,以便视图函数执行出错
-2、使用方式
    -写一个函数,可以把所有的异常都用一个异常信息捕获到返回给前端
    def common_exception_handler(exc,context):
    response=exception_handler(exc,context)
    if response is None:
        #错误日志记录日志
        # , 'args': (), 'kwargs': {}, 'request': }
        print(context['view']) # 哪个视图函数出错
        view=context['view']
        request=context['request']
        print(context['request'])  # 当此请求的request对象
        print(str(view))
        print(request.path)
        print(request.method)
        print(request.META.get('REMOTE_ADDR'))
        #记录日志(django日志)
        #sentry 这就是日志追踪的软件
        print('执行视图函数出错,用户请求地址都是:%s,用户的IP是%s'%(request.path,request.META['REMOTE_ADDR']))
        response=Response({'code':999,'dateil':str(exc)},status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    return response

    -在setting中配置
            REST_FRAMEWORK = {
                'EXCEPTION_HANDLER':'app01.utils.common_exception_handler'
            }

3、封装Response

-1、以后都使用自己封装的response
    class APIResponse(Response):
    def __init__(self, code=100, msg='成功', data=None, status=None, headers=None, content_type=None, **kwargs):# **kwargs用来接收其他的多余的传过来的参数,显示在前端
        dic = {'code': code, 'msg': msg}
        if data:
            dic['data'] = data

        dic.update(kwargs) # 这里使用update来更新字典
        super().__init__(data=dic, status=status,
                         template_name=None, headers=headers,
                         exception=False, content_type=content_type)

-2、使用:在视图类中返回的数据就这么用
        return APIResponse(code=100,msg='查询成功',data=ser.data,count=200,next='http://wwwa.asdfas')
        # 返回的数据是自己封装的APIResponse里需要的参数,并且可以传入多余的自己想显示在前端的参数,都会被接收到

4、自动生成接口文档

-1、借助于第三方:coreapi,swagger
-2、在路由中
    from rest_framework.documentation import include_docs_urls
    path('docs/', include_docs_urls(title='图书管理系统api'))
    其他的视图路由要配好,然后视图中要写详细的注释,用法。就会自动在docs路径下生成文档
-3、 在配置文件中
    REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
    }
-4、写视图类(需要加详细的注释)
    class BookListCreateView(ListCreateAPIView):
        """
        get:
        返回所有图书信息.
        asdfasfda

        post:
        新建图书.
        """
        queryset = Student.objects.all()
        serializer_class = StudentSerializer
-5、只需要在浏览器输入,就可以看到自动生成的接口文档
    http://127.0.0.1:8000/docs/

你可能感兴趣的:(2020-12-14 drf--分页、全局异常捕获、接口文档)