一 过滤Filtering
详细链接:
http://www.xuexianqi.top/archives/584.html
对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。
1
|
pip install django-filter
|
在配置文件中增加过滤后端的设置:
1 2 3 4 5 6 7 8 9
|
INSTALLED_APPS = [ ... 'django_filters', # 需要注册应用, ]
REST_FRAMEWORK = { ... 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',) }
|
在视图中添加filter_fields属性,指定可以过滤的字段
1 2 3 4 5 6
|
classStudentListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer filter_fields = ('age', 'sex')
# 127.0.0.1:8000/four/students/?sex=1
|
二 排序
对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。
使用方法:
在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter
过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。
前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。
示例:
1 2 3 4 5 6 7 8 9
|
classStudentListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer filter_backends = [OrderingFilter] ordering_fields = ('id', 'age')
# 127.0.0.1:8000/books/?ordering=-age # -id 表示针对id字段进行倒序排序 # id 表示针对id字段进行升序排序
|
如果需要在过滤以后再次进行排序,则需要两者结合!
1 2 3 4 5 6 7 8 9 10 11 12
|
from rest_framework.generics import ListAPIView from students.models import Student from .serializers import StudentModelSerializer from django_filters.rest_framework import DjangoFilterBackend class Student3ListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer filter_fields = ('age', 'sex') # 因为局部配置会覆盖全局配置,所以需要重新把过滤组件核心类再次声明, # 否则过滤功能会失效 filter_backends = [OrderingFilter,DjangoFilterBackend] ordering_fields = ('id', 'age')
|
REST framework提供了分页的支持。
我们可以在配置文件中设置全局的分页方式,如:
1 2 3 4
|
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 100 # 每页数目 }
|
也可通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas
属性来指明。
1 2 3 4 5 6 7 8
|
classLargeResultsSetPagination(PageNumberPagination): page_size = 1000 page_size_query_param = 'page_size' max_page_size = 10000 class BookDetailView(RetrieveAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer pagination_class = LargeResultsSetPagination
|
注意:如果在视图内关闭分页功能,只需在视图内设置
1
|
pagination_class = None
|
可选分页器
1) PageNumberPagination
前端访问网址形式:
1
|
GET http://127.0.0.1:8000/students/?page=4
|
可以在子类中定义的属性:
- page_size 每页数目
- page_query_param 前端发送的页数关键字名,默认为”page”
- page_size_query_param 前端发送的每页数目关键字名,默认为None
- max_page_size 前端最多能设置的每页数量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
# APIView from rest_framework.pagination import PageNumberPagination # 一 基本使用:url=url=http://127.0.0.1:8000/pager/?page=2&size=3,size无效 classPager(APIView): defget(self,request,*args,**kwargs): # 获取所有数据 ret=models.Book.objects.all() # 创建分页对象 page=PageNumberPagination() # 在数据库中获取分页的数据 page_list=page.paginate_queryset(ret,request,view=self) # 对分页进行序列化 ser=BookSerializer1(instance=page_list,many=True) return Response(ser.data) # 二 自定制 url=http://127.0.0.1:8000/pager/?page=2&size=3 # size=30,无效,最多5条 classMypage(PageNumberPagination): page_size = 2 page_query_param = 'page' # 定制传参 page_size_query_param = 'size' # 最大一页的数据 max_page_size = 5 classPager(APIView): defget(self,request,*args,**kwargs): # 获取所有数据 ret=models.Book.objects.all() # 创建分页对象 page=Mypage() # 在数据库中获取分页的数据 page_list=page.paginate_queryset(ret,request,view=self) # 对分页进行序列化 ser=BookSerializer1(instance=page_list,many=True) # return Response(ser.data) # 这个也是返回Response对象,但是比基本的多了上一页,下一页,和总数据条数(了解即可) return page.get_paginated_response(ser.data)
#ListAPIView
# 声明分页的配置类 from rest_framework.pagination import PageNumberPagination classStandardPageNumberPagination(PageNumberPagination): # 默认每一页显示的数据量 page_size = 2 # 允许客户端通过get参数来控制每一页的数据量 page_size_query_param = "size" max_page_size = 10 # 自定义页码的参数名 page_query_param = "p"
classStudentAPIView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer pagination_class = StandardPageNumberPagination
# 127.0.0.1/four/students/?p=1&size=5
|
2)LimitOffsetPagination
前端访问网址形式:
1
|
GET http://127.0.0.1/four/students/?limit=100&offset=400
|
可以在子类中定义的属性:
- default_limit 默认限制,默认值与
PAGE_SIZE
设置一直
- limit_query_param limit参数名,默认’limit’
- offset_query_param offset参数名,默认’offset’
- max_limit 最大limit限制,默认None
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
# APIView # http://127.0.0.1:8000/pager/?offset=4&limit=3 from rest_framework.pagination import LimitOffsetPagination # 也可以自定制,同简单分页 classPager(APIView): defget(self,request,*args,**kwargs): # 获取所有数据 ret=models.Book.objects.all() # 创建分页对象 page=LimitOffsetPagination() # 在数据库中获取分页的数据 page_list=page.paginate_queryset(ret,request,view=self) # 对分页进行序列化 ser=BookSerializer1(instance=page_list,many=True) # return page.get_paginated_response(ser.data) return Response(ser.data) #ListAPIView from rest_framework.pagination import LimitOffsetPagination classStandardLimitOffsetPagination(LimitOffsetPagination): # 默认每一页查询的数据量,类似上面的page_size default_limit = 2 limit_query_param = "size" offset_query_param = "start"
classStudentAPIView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer # 调用页码分页类 # pagination_class = StandardPageNumberPagination # 调用查询偏移分页类 pagination_class = StandardLimitOffsetPagination
|
3)CursorPagination
前端访问网址形式:
1
|
GET http://127.0.0.1/four/students/?cursor=cD0xNQ%3D%3D
|
可以在子类中定义的属性:
- cursor_query_param:默认查询字段,不需要修改
- page_size:每页数目
- ordering:按什么排序,需要指定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
#APIView from rest_framework.pagination import CursorPagination # 看源码,是通过sql查询,大于id和小于id classPager(APIView): defget(self,request,*args,**kwargs): # 获取所有数据 ret=models.Book.objects.all() # 创建分页对象 page=CursorPagination() page.ordering='nid' # 在数据库中获取分页的数据 page_list=page.paginate_queryset(ret,request,view=self) # 对分页进行序列化 ser=BookSerializer1(instance=page_list,many=True) # 可以避免页码被猜到 return page.get_paginated_response(ser.data) # ListAPIView classMyCursorPagination(CursorPagination): page_size=2 ordering='-id' from rest_framework.generics import ListAPIView classAuthorListView(ListAPIView): serializer_class = serializers.AuthorModelSerializer queryset = models.Author.objects.filter(is_delete=False) pagination_class =MyCursorPagination
|
应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination class MyPageNumberPagination(PageNumberPagination): page_size = 2 page_query_param = 'page' # 定制传参 page_size_query_param = 'size' # 最大一页的数据 max_page_size = 5
classMyLimitOffsetPagination(LimitOffsetPagination): default_limit = 2 # 最大一页的数据 max_limit = 5 classMyCursorPagination(CursorPagination): page_size=2 ordering='-id' from rest_framework.generics import ListAPIView classAuthorListView(ListAPIView): serializer_class = serializers.AuthorModelSerializer queryset = models.Author.objects.filter(is_delete=False) pagination_class =MyCursorPagination
|
分页器三种如何使用
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) # 返回数据
View Code
四 异常处理 Exceptions
REST framework提供了异常处理,我们可以自定义异常处理函数。
4.1 使用方式
1 2 3 4 5 6 7 8 9 10 11
|
from rest_framework.views import exception_handler
defcustom_exception_handler(exc, context): # 先调用REST framework默认的异常处理方法获得标准错误响应对象 response = exception_handler(exc, context)
# 在此处补充自定义的异常处理 if response isNone: response.data['status_code'] = response.status_code
return response
|
在配置文件中声明自定义的异常处理
1 2 3
|
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler' }
|
如果未声明,会采用默认的方式,如下
rest_frame/settings.py
1 2 3
|
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler' }
|
4.2 案例
补充上处理关于数据库的异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
from rest_framework.views import exception_handler from rest_framework.response import Response from rest_framework.views import exception_handler as drf_exception_handler from rest_framework import status from django.db import DatabaseError
def exception_handler(exc, context): response = drf_exception_handler(exc, context)
if response is None: view = context['view'] print('[%s]: %s' % (view, exc)) if isinstance(exc, DatabaseError): response = Response({'detail': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE) else: response = Response({'detail': '未知错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return response
# 在setting.py中配置 REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'app01.ser.exception_handler' }
|
4.3 REST framework定义的异常
- APIException 所有异常的父类
- ParseError 解析错误
- AuthenticationFailed 认证失败
- NotAuthenticated 尚未认证
- PermissionDenied 权限决绝
- NotFound 未找到
- MethodNotAllowed 请求方式不支持
- NotAcceptable 要获取的数据格式不支持
- Throttled 超过限流次数
- ValidationError 校验失败
也就是说,很多的没有在上面列出来的异常,就需要我们在自定义异常中自己处理了。
自动生成接口文档
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/
View Code
全局异常
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'
}
View Code