-drf-过滤排序分页异常处理
一 过滤Filtering
1 内置过滤
# 模块导入
from rest_framework.filters import SearchFilter
1.过滤目的:筛选查询结果(模糊匹配,只要含有就匹配出来)
2.内置筛选使用
-在视图类中配置
filter_backends =[SearchFilter,]
# 匹配所有字段进行过滤筛选
-http://127.0.0.1:8000/books/?search=i
# 只要有一个对象中的不论任何字段模糊匹配到i,就过滤出来
filter_backends = [SearchFilter, ]
search_fields = ('title',)
# 匹配title字段进行过滤筛选
-http://127.0.0.1:8000/books/?search=i
# 这样是只要有一个对象中的title字段模糊匹配到i,就过滤出来
2 第三方扩展的过滤功能
对于列表数据可能要根据字段进行过滤,我们可以通过添加django-filter扩展来增强支持
# 安装
pip install django-filter :最新版本(2.4.0)要跟django2.2以上搭配
在配置文件中增加过滤后端的设置:
INSTALLED_APPS = [
...
'django_filters', # 需要注册应用,
]
REST_FRAMEWORK = {
...
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
在视图中添加filter_fields属性,指定可以过滤的字段
# 导入模块
from django_filters.rest_framework import DjangoFilterBackend
class BookInfo(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
filter_backends = [DjangoFilterBackend, ]
filter_fields = ('title', 'price') # 与内置的search方法不同
# 输入的url
-http://127.0.0.1:8000/books/?title=i 或 http://127.0.0.1:8000/books/?price=1
# 见名知意:可以直接在?字段=匹配内容 的方式在book表中指定的该字段模糊匹配过滤出数据对象
二 排序
对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。
使用方法:
在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter
过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。
前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。
举例:
# 导入模块
from rest_framework.filters import OrderingFilter
class BookInfo(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
filter_backends = [OrderingFilter, ]
ordering_fields = ('price',) # 指定字段,默认升序排序
-http://127.0.0.1:8000/books/?ordering=price # 也需要在url配置相应的参数
# ordering_fields = ('-price',) # 降序排序
如果需要在过滤以后再次进行排序,则需要两者结合
class BookInfo(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
throttle_classes = [AnonRateThrottle, UserRateThrottle]
filter_backends = [DjangoFilterBackend, OrderingFilter]
filter_fields = ('publish',)
ordering_fields = ('price',)
-http://127.0.0.1:8000/books/?publish=1&ordering=price
# 在过滤出出版社publish=1后,将过滤对象以Price升序排序
三 分页Pagination
REST framework提供了分页的支持。
我们可以在配置文件中设置全局的分页方式,如:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100 # 每页数目
}
注意:如果在视图内关闭分页功能,只需在视图内设置
pagination_class = None
也可以通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas
属性来指明。
# 导入模块
from rest_framework.pagination import PageNumberPagination
from rest_framework.generics import ListAPIView
# myauth.py
class ResultSetPagination(PageNumberPagination):
page_size = 2 # 每页显示的条数
page_query_param = 'page' # 前端返回来查找页数的关键字
max_page_size = 30 # 前端显示的最多的页数
# views.py
# path('books/', views.BookInfo.as_view({"get": "list"}))
class BookInfo(ListModelMixin, GenericViewSet): # 只进行查询所有数据的接口不用写get方法
# 路由已经进行了配置
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
pagination_class = myauth.ResultSetPagination
1 PageNumberPagination:普通分页
前端访问网址形式:
GET http://127.0.0.1:8000/books/?page=3&size=1
找到第三页从上到下数的第一条数据
可以在子类中定义的属性:
- page_szie 每页的条数,后端默认的,如果前端有指定按照前端指定的
- page_query_param 前端发送页数的关键字名,默认为“page”
- page_size_query_param 前端发送的每页条数的关键字名,默认为None
- max_page_size 前端最多能设置的分页的总数
from rest_framework.pagination import PageNumberPagination
class ResultSetPagination(PageNumberPagination):
page_size = 2 # 每页显示的条数
page_query_param = 'page' # 前端返回来查找页数的关键字
max_page_size = 30 # 前端显示的最多的页数
page_size_query_param = 'size' # 前端发送的每页条数的关键字名
# views.py
class BookInfo(ListModelMixin, GenericViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
pagination_class = myauth.ResultSetPagination
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 LimitOffsetPagination:偏移分页
前端访问网址形式:
GET http://127.0.0.1/books/?limit=2&offset=4
找到第四条数据然后以两条数据为一页进行分页(起始数据从5开始不包含4)
可以在子类中定义的属性:
- deault_limit 每页条数,后端默认的,如果前端有指定按照前端指定的
- limit_query_param 前端指定每页查询多少条的关键字
- offset_query_param 前端指定查询的起始位置的关键字
- max_limit 查询时最多返回多少条
from rest_framework.pagination import LimitOffsetPagination
# auth.py
class LimitSetPagination(LimitOffsetPagination):
default_limit = 3
limit_query_param = 'limit'
offset_query_param = 'offset'
# views.py
class BookInfo(ListModelMixin, GenericViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
pagination_class = myauth.LimitSetPagination
APIView的分页模式
class Pager(APIView):
def get(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)
3 CursorPagination:游标分页
速度快:检索数据方式,是在当前页面向上或向下检索
GET http://127.0.0.1:8000/books/?cursor=bz0z&page=3
# cursor游标标识跳转的当前页面,游标卡在当前页面的上下,所以查询速度很快,直接在当前游标向上或向下检索。但是也限制了不能直接跳转到其他页面只能上下。
可以在子类中定义的属性:
- cursor_query_param: 默认查询字段,不需要修改,前端指定查询的关键字
- page_size:每页数目,后端默认的,如果前端有指定按照前端指定的
- ordering:按什么排序,需要指定
- page_size_query_param 前端发送的每页条数的关键字名,默认为None
from rest_framework.pagination import CursorPagination
# auth.py
class CursorSetPagination(CursorPagination):
page_size = 2 # 默认页面条数
ordering = 'id'
cursor_query_param = 'cursor' # 默认cursor 可以不写
page_size_query_param = 'page' # 前端指定页面条数,则按前端指定的来
# views.py
class BookInfo(ListModelMixin, GenericViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
pagination_class = myauth.CursorSetPagination
APIView分页模式
class Pager(APIView):
def get(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)
四 异常处理Exceptions
REST framework提供了异常处理,我们可以自定义异常处理函数
1 使用方式
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
print(str(exc))
# 先调用drf默认的异常处理方式获得标准错误响应对象
response = exception_handler(exc, context)
# 在此处补充自定的异常处理,返回前端
if response is None: # 没有返回值代表有异常
response = Response({'detail': str(exc)})
return response
在配置文件中声明自定义的异常处理
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'app10.myauth.custom_exception_handler',
}
如果未声明,会采用默认的方式,如下
rest_frame/settings.py
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
2 补充上处理关于数据库的异常
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'
}
3 REST framework定义的异常
- APIException 所有异常的父类
- ParseError 解析错误
- AuthenticationFailed 认证失败
- NotAuthenticated 尚未认证
- PermissionDenied 权限决绝
- NotFound 未找到
- MethodNotAllowed 请求方式不支持
- NotAcceptable 要获取的数据格式不支持
- Throttled 超过限流次数
- ValidationError 校验失败