Fork me on GitHub

-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 校验失败
posted @ 2020-11-17 18:02  artherwan  阅读(154)  评论(0编辑  收藏  举报