day88

1 自定制过滤器
2 分页器(三种)重点如何使用
3 全局异常
4 封装Response对象
5 自动生成接口文档

## 0 自定制过滤器

```python
基于django-filter扩写

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





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

```python
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/?limit=100&offset=1
                    
                    
 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) # 返回数据
```





## 2 全局异常

```python
1 统一接口的返回方式,即便视图函数执行出错
2 使用方式
    -写一个函数
    def common_exception_handler(exc, context):
        response = exception_handler(exc, context)
        if response is None:
            response = Response({'code':999,'detail': '未知错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        return response
       -在setting中配置
        REST_FRAMEWORK = {
            'EXCEPTION_HANDLER':'app01.utils.common_exception_handler'
        }
```



## 3 封装Response对象

```python
1 以后都使用自己封装的response
class APIResponse(Response):
    def __init__(self, code=100, msg='成功', data=None, status=None, headers=None, content_type=None, **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')

```



## 4 自动生成接口文档

```python
1 借助于第三方:coreapi,swagger
2 在路由中
    from rest_framework.documentation import include_docs_urls
    path('docs/', include_docs_urls(title='图书管理系统api'))
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/
```
# settings.py
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'app01.utils.common_exception_handler',
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',    # 自动生成接口文档的配置
}


# urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
from rest_framework.routers import SimpleRouter

router = SimpleRouter()
router.register('students', views.StudentView)

from rest_framework.documentation import include_docs_urls

urlpatterns = [
    path('admin/', admin.site.urls),
    path('student_apiview/', views.StudentApiView.as_view()),
    path('docs/', include_docs_urls(title='图书管理系统api')),    # 访问docs就可以看见自动生成的接口文档
    path('books/', views.BookListCreateView.as_view()),
]
urlpatterns += router.urls


# views.py
from django.shortcuts import render

# Create your views here.


from rest_framework.generics import ListAPIView
from app01.serializer import StudentSerializer
from app01.models import Student
from rest_framework.viewsets import ViewSetMixin, GenericViewSet
from rest_framework.mixins import ListModelMixin
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination


class MyPageNumberPagination(PageNumberPagination):
    page_size = 3                       # 每页默认显示的条数(若未传size参数,则以默认值输出)
    page_query_param = 'page'           # 查询参数
    page_size_query_param = 'size'      # 查询时指定每页显示的条数
    max_page_size = 5                   # 每页最大显示条数(优先级高于用户指定)


class MyLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 2  # 默认条数
    limit_query_param = 'limit'  # 查询时,指定查询多少条
    offset_query_param = 'offset'  # 查询时,指定的起始位置是哪
    max_limit = 5  # 查询时,最多返回多少条


class MyCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'  # 查询的时候,指定的查询方式
    page_size = 2  # 每页显示多少条
    ordering = 'id'  # 排序方式,一定要指定排序方式,就是model中的可以排序的字段
    # page_size_query_param = 'size'  # 查询的时候指定每页显示多少条
    # max_page_size = 5  # 每页最多显示多少条


# class StudentView(GenericViewSet,ListAPIView):
class StudentView(GenericViewSet, ListModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    # 普通分页(用的多)
    pagination_class = MyPageNumberPagination
    # 偏移分页
    # pagination_class = MyLimitOffsetPagination
    # 游标分页
    # pagination_class = MyCursorPagination


# 如果继承Apiview,分页方式的使用
from rest_framework.views import APIView
from rest_framework.response import Response
# class StudentApiView(APIView):
#
#     def get(self,request):
#         # 自己进行分页
#         student_list=Student.objects.all()
#         # 进行分页
#         # 实例化得到分页对象
#         # page=MyPageNumberPagination()
#         # page=MyLimitOffsetPagination()
#         page=MyCursorPagination()
#         res=page.paginate_queryset(student_list,request,self)
#         10/0
#         ser=StudentSerializer(res,many=True)
#
#         # 把分页后的数据放到里面
#         # return Response(ser.data)
#         return page.get_paginated_response(ser.data)


from app01.utils import APIResponse


class StudentApiView(APIView):

    # def get(self,request):
    #     res={'code':100,'msg':'成功','data':None}
    #     student_list=Student.objects.all()
    #     ser=StudentSerializer(student_list,many=True)
    #
    #     res['data']=ser.data
    #     return Response(res)
    def get(self, request):
        student_list = Student.objects.all()
        ser = StudentSerializer(student_list, many=True)
        return APIResponse(code=100, msg='查询成功', data=ser.data, count=200, next='http://www.asdfas')


from rest_framework.generics import ListCreateAPIView, ListAPIView


class BookListCreateView(ListCreateAPIView):
    """
    get:
    返回所有图书信息.
    asdfasfda

    post:
    新建图书.您必须传name,age,和sex
    sex是数字,1表示男,2表示女
    """
    queryset = Student.objects.all()
    serializer_class = StudentSerializer


class BookListView(ListAPIView):
    """
    返回所有图书信息.
    """


# utils.py
from rest_framework import status
from rest_framework.views import exception_handler
from rest_framework.response import Response
from django.db import DatabaseError


# def common_exception_handler(exc, context):
#     response = exception_handler(exc, context)
#     # 在此处补充自定义的异常处理
#     if response is None:
#         view = context['view']
#         print('[%s]: %s' % (view, exc))
#         if isinstance(exc, DatabaseError):
#             response = Response({'code':101,'detail': '数据库错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
#         elif isinstance(exc,ZeroDivisionError):
#             response = Response({'code':102,'detail': '除以0的错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
#         else:
#             response = Response({'code':999,'detail': '未知错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
#
#     return response


def common_exception_handler(exc, context):
    response = exception_handler(exc, context)
    if response is None:
        # 错误信息记录日志      context
        # {<app01.views.StudentApiView object at 0x0000015D4DD44700>, 'args': (), 'kwargs': {},
        # 'request': <rest_framework.request.Request: GET '/student_apiview/'>}
        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, 'detail': str(exc)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    return response


from rest_framework.response import Response


# class APIResponse(Response):
#     def __init__(self, code=100, msg='成功', data=None, status=None, headers=None, content_type=None, **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)


class APIResponse(Response):
    def __init__(self, code=100, msg='成功', data=None, status=None, headers=None, content_type=None, **kwargs):
        dic = {'code': code, 'msg': msg}
        if data:
            dic['data'] = data
        dic.update(kwargs)
        super().__init__(data=dic, status=status, template_name=None, headers=headers, exception=False,
                         content_type=content_type)

 

posted @ 2020-11-14 23:55  板鸭没有腿  阅读(149)  评论(0)    收藏  举报