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
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