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)

浙公网安备 33010602011771号