【Django】DRF过滤、排序、分页的简单使用

1.过滤

我们可以安装django-filter来控制过滤操作,只要安装好之后再配置一下即可

安装

pip install django-filter

settings.py

INSTALLED_APP = [
  ....
  'django_filters',
]

# REST_FRAMEWORK配置项对"drf接口"进行全局配置
# 全局配置针对所有的drf视图(接口)
REST_FRAMEWORK = {
    
    
    # ......
    # 过滤后端,针对所有资源视图的self.list
    'DEFAULT_FILTER_BACKENDS': (
        'django_filters.rest_framework.DjangoFilterBackend',
    )
}

views.py

class BooksView(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer
	...
    # 指定要过滤的字段,如bread、btitle两个字段
    filterset_fields = ['btitle','bread']

浏览器访问:GET /books/?btitle=雪山飞狐&bread=
当访问的时候不指定过滤条件,默认返回全部

补充:条件过滤,大于、小于、模糊查询等
可以参考官网的帮助文档 https://django-filter.readthedocs.io/en/latest/guide/usage.html#the-filter

只要修改filterset_fields成一个列表,每个字段支持的查询方式用键值对套列表的方式表示

class BooksView(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer
	...
    # 指定要过滤的字段
    filterset_fields = {
    
    
        "btitle":["exact","icontains"],
        "bread":["exact","lt","gt","lte","gte"]
    }
关键字 说明 表示
exact 精确查询 字段=值
icontains 模糊查询(包含) 字段__icontains=值
gt、lt、gte、lte 大于、小于、大于等于、小于等于 字段__gte=值

浏览器访问 :GET books/?btitle__icontains=湖&bread__gte=20(书名有“湖”字,且阅读量大于等于20)

2.排序

settings.py

REST_FRAMEWORK = {
    
    
    ...
    'DEFAULT_FILTER_BACKENDS': (
        # 'django_filters.rest_framework.DjangoFilterBackend', # 指定字段过滤
        'rest_framework.filters.OrderingFilter', # 排序后端
    )
}

views.py

class BooksView(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer
	...
    # GET + /books/?ordering=bread  升序
    # GET + /books/?ordering=-bread 降序
    ordering_fields = ['bread', 'bcomment', 'bpub_date']

3.分页

3.1 PageNumberPagination

settings.py

扫描二维码关注公众号,回复: 11848106 查看本文章
REST_FRAMEWORK = {
    
    
	...
    # 分页后端
    # 方式一:PageNumberPagination
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 3  # 后端定义默认每页数目
}

views.py

class BooksView(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

	...
    # 分页
    # 对应方式一
    pagination_class = PageNumberPagination

浏览器访问第2页:GET /books/?page=2

3.2 PageNumberPagination(自定义)

自定义很简单,只需要新建一个类继承PageNumberPagination,然后重写它的属性即可

views.py

class MyPageNum(PageNumberPagination):
    # 约定:/books/?page=1&pagesize=5
    # 通过类属性,定义查询字符串参数
    page_query_param = 'page' # 指定查询字符串参数key为'page',传递取第几页
    page_size_query_param = 'pagesize' # 指定查询字符串参数key为'pagesize',传递每页数目
    page_size = 5 # 指定后端默认按照每页几个划分
    max_page_size = 10 # 每页数目的最大值
	
class BooksView(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

	...
    # 分页
    pagination_class = MyPageNum

浏览器访问:GET /books/?page=1&pagesize=3,每页3个,取第一页,若pagesize不传,则采用类里定义的默认值

3.3 LimitOffsetPagination

settings.py

REST_FRAMEWORK = {
    
    
    ...
    # 方式二:LimitOffsetPagination:,根据偏移offset个数据,取limit条数据
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.LimitOffsetPagination',
}

views.py

class BooksView(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

	...
    # 分页
    # 对应方式二
    pagination_class = LimitOffsetPagination

浏览器访问 GET /books/?limit=2&offset=3(取2条,偏移3条,即取第5、6条)

3.4 LimitOffsetPagination(自定义)

views.py

class MyLimitOffset(LimitOffsetPagination):
    # 约定:/books/?offset=5&limit=2
    # 通过类属性,定义查询字符串参数
    limit_query_param = 'limit'
    offset_query_param = 'offset'
    default_limit = 5
    max_limit = 10
	
class BooksView(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

	...
    # 分页
    pagination_class = MyLimitOffset

浏览器访问:GET /books/?limit=2&offset=3

3.5 自定义分页的响应结果

使用上面的方法返回的响应结果的格式是固定的,大概是以下的样子

{
    
    
    "count": 6,
    "next": "http://127.0.0.1:8000/books/?limit=2&offset=5",
    "previous": "http://127.0.0.1:8000/books/?limit=2&offset=1",
    "results": [
        ...
    ]
}

但是在实际开发中,一般都会有不一样的返回格式,所以我们要自定义响应格式

通过Debug我们可以发现默认分页器大概响应过程如下
在这里插入图片描述
大概得到两个结论:

  • GenericAPIView里面的get_paginated_response()控制了分页返回的结果
  • 分页器中的get_paginated_response()函数控制了分页返回的结果;

所以,我们可以重写get_paginated_response()实现自定义分页

方案1: 重写资源视图中的get_paginated_response()

class BooksView(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

	...
    # 分页
    pagination_class = MyLimitOffset
	# 自定义响应格式
    def get_paginated_response(self, data):
        return Response(data={
    
    
            'code':0,
            'errmsg':'ok',
            'lists':data
        })

这种方法只对当前视图有用,并非全部视图,若要作用于所有应用此分页器的视图,可以使用方案2

方案2: 重写分页器中的get_paginated_response()

class MyPageNum(PageNumberPagination):
    # 约定:/books/?page=1&pagesize=5
    # 通过类属性,定义查询字符串参数
    page_query_param = 'page' # 指定查询字符串参数key为'page',传递取第几页
    page_size_query_param = 'pagesize' # 指定查询字符串参数key为'pagesize',传递每页数目
    page_size = 5 # 指定后端默认按照每页几个划分
    max_page_size = 10 # 每页数目的最大值
	
	# 重写分页器中该函数,作用于所有使用当前分页器的资源视图
    def get_paginated_response(self, data):
        return Response(data={
    
    
            'code': 0,
            'errmsg': 'ok',
            'lists': data
        })	

class BooksView(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

	...
    # 分页
    pagination_class = MyPageNum

猜你喜欢

转载自blog.csdn.net/qq_39147299/article/details/108771405