DRF | 入门第八天 排序、过滤、分页

180 阅读3分钟

排序和过滤

导入排序和过滤模块

from rest_framework.filters import SearchFilter, OrderingFilter

在视图类里面添加类属性

方式一:(内置的)

内置的过滤组件只支持search模糊匹配。不支持精准匹配。

举例http://127.0.0.1:8000/publish/?search=上, 在URL地址中的过滤字段。

filter_backends = [SearchFilter, OrderingFilter]  
search_fields = ['name', 'addr']  
order_fields = ['id']

方式二:(第三方)

方式二,借助第三方模块。 精准匹配--->Django.filter pip3 install django-filter

基本方法跟方法一一样。

首先导入模块from django_filters.rest_framework import DjangoFilterBackend

设置类属性filter_backends = [DjangoFilterBackend]filtersets_fields = ['name']

在URL地址中搜索:name=

你的过滤条件是什么就搜索什么。

方式三:(自定义)

有的时候,内置组件和第三方组件可能都没有办法满足我们的需求或者不完美,这个时候需要我们自定义,自己来写一个过滤器。

'''  
1. 先创建一个filter.py文件专门用来写自定义的过滤器  
2. 导入模块,继承模块,重写方法  
'''  
  
from rest_framework.filters import BaseFilterBackend  
  
class PublishFilter(BaseFilterBackend):  
    def filter_queryset(self, request, queryset, view):  
    # 基于query_set进行过滤,过滤后返回即可  
    # http://127.0.0.1:8000/publish/?addr=北京市 名字有它的直接查出来  

    search_params = request.query_params.get('name')  
    if search_params:  
        queryset = queryset.filter(name__contains=search_params)  
    return queryset

添加或者筛选条件,导入from django.db.models import Q

回到视图层直接设置filter_backends = [PublishFilter] 就好

继承APIView写过滤类

继承GenericAPIView写过滤类

写多个过滤类时,它们的执行过滤顺序是从左往右, 依次执行的。大原则,配置多个过滤类时候,第一个尽量放过滤越多的过滤类。

分页

针对 查询的所有接口

展现形式: Web 下一页,下一页 APP 下拉 下拉

必须继承GenericAPIView

第一种方法

导入from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination

class CommonPageNumberPagination(PageNumberPagination):  
    '''  
    http://api.example.org/accounts/?page=4  
    http://api.example.org/accounts/?page=4&page_size=100  
    '''  
    # 重写几个类属性  
    page_size = 2 # --->每页显示几条数据  
    page_query_param = 'page' # --->指定页数的Key  
    page_size_query_param = 'size' # --->可以指定每页显示多少条  
    max_page_size = 5 # --->每页最多显示多少条

视图层里面只需要添加这个类pagination_class = CommonPageNumberPagination 切记,这个不能以列表的形式添加,否则会报错。

结果展示:

{
    "count": 11,
    
    "next": "http://127.0.0.1:8000/book/?page=4",
    "previous": "http://127.0.0.1:8000/book/?page=2",
    
    "results": [
        {
            "id": 5,
            "title": "三字经",
            "price": "8.8",
            "is_delete": 0,
            "publish": 2,
            "author": []
        },
        {
            "id": 6,
            "title": "道德经",
            "price": "55",
            "is_delete": 0,
            "publish": 2,
            "author": []
        }
    ]
}

第二种方法

定义类,重写属性

class CommonLimitOffsetPagination(LimitOffsetPagination):  

    '''  
    http://api.example.org/accounts/?limit=100 从开始取100条  
    http://api.example.org/accounts/?offset=400&limit=100 从第400条开始取后面100条  
    '''  

    # 重新写几个属性  
    default_limit = 3 # ---> 默认每页显示多少条  
    limit_query_param = 'limit' # --->每页显示多少条的查询条件  
    offset_query_param = 'offset' # --->  
    max_limit = 5 # --->限制最多取5条

第三种方法(主要用于APP应用)

高效率

class CommonCursorPagination(CursorPagination):  
# 只能上一页和下一页,不能指定跳转到中间的某页,效率高,大数据量的时候用它  
cursor_query_param = 'cursor' # 查询条件  
page_size = 2 # 每页显示两条  
ordering = 'id' # 按照id排序,这个必须是表中字段

异常处理

三大认证中的异常

三大认证,视图类的方法中执行出错,都会被全局异常捕获

-认证类,认证不通过,抛异常,前端没有看到问题,只是返回了提示信息--->处理了DRF的额异常

DRF全局异常处理,它只会把DRF的异常处理掉,统一返回个是,但是Django原生的异常和Python的异常都不胡处理。

而我们要做的就是统一化所有异常。

exceptions.py

'''  
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'  
'''  
  
from rest_framework.views import exception_handler  
from rest_framework.response import Response  
  
def common_exceptions(exc, context):  
    # 如果DRF的异常捕捉能处理,我们就不用处理了  
    res = exception_handler(exc, context)  
    if not res:  
        return Response({'code':8888, 'msg':'❌非DRF程序错误---%s'%str(exc)})  
    else:  
        return Response({'code':8888, 'msg':f'❌DRF错误---{res.data.get("detail")}'})

settings.py

REST_FRAMEWORK = {  
    'EXCEPTION_HANDLER': 'app01.exceptions.common_exceptions'
    }