原文地址
这是第三篇内容,接下来我们介绍一下如何使用REST framework框架自带的一些功能来丰富你的API。
我们都知道利用API获取资源的场景下,不止是傻傻的查询所有数据,然后对数据进程采集。我们如果要按照要求来筛选我们要的数据呢?
比如,我们不想要一次显示这么多条数据,我们在前台不需要加载这么多。或者,我们需要有条件的去筛查数据,或者有顺序的去取数据。
这些在REST framework都已经帮你把功能设计好了,只需要引用和稍作定制就可以使用了。
我们分别来简单的介绍一下REST framework的分页、搜索、排序的使用方法。
实验我们还是拿上次试验的那个Student类来做这次的实验。
我们在实际开发当中,不可能直接一个视图下显示所有的数据,一般web端会用分页来划分,而手机端一般是用“上拉加载”的办法来进行新增数据的操作。这样的操作无疑是减轻了前后台两端对数据库操作的工作量,让用户需要吃多少就拿多少,不会造成大量的资源浪费。
REST framework为我们提供了比较不错的分页功能,
全局分页
分页的方式有分两种,一种是全局设置,在setting.py下配置即可设置全局分页的功能。
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination'
}
分类中有许多属性可以自己设置。网上有位大佬整理的很不错,大家可以看看他写的内容。
PageNumberPagination类包括可以覆盖以修改分页样式的许多属性,要设置这些属性,应覆盖PageNumberPagination类,然后如上所示启用自定义分页类。
django_paginator_class:使用的Django Paginator类,默认是django.core.paginator.Paginator,对大部分用例是适用的。
page_size:数值,页面大小,默认是全局PAGE_SIZE的值。
page_query_param:字符串,查询参数的名称,默认是'page'page_size_query_param:字符串,请求设置页面大小的参数名称,默认是None,表示客户端可能无法控制请求的页面大小。
max_page_size:字符串,最大允许请求的页面大小, 此属性仅在page_size_query_param也被设置时有效。
last_page_strings:字符串列表或者元组,默认是('last',)template:分页控件使用的模板的名称,可以覆盖或设置为None,默认为"rest_framework/pagination/numbers.html"
———————————————注明出处分割线————————————————————————
作者:Ccccolin_aha链接:https://www.jianshu.com/p/95573642e310
來源:简书简书著作权归作者所有,
任何形式的转载都请联系作者获得授权并注明出处。
设置完全局分页后,只需要输入URL的形式就可以访问
http://127.0.0.1:8000/api/student/?page=2
自定义分页
当然,这里我们更推荐的是自定义分页的方法,毕竟这种方法毕竟灵活。在实际开发当中,也不是所有的资源都需要进行分页的,或者不是所有资源都是一样的分页属性,有的一页10条,有的一页只需要3条,这样该怎么做呢?
我们先在views.py下定义好一个分页的配置:
# 记得要导包啊
from rest_framework import viewsets,filters,pagination
class PageSet(pagination.PageNumberPagination):
#每页显示多少个
page_size = 3
#默认每页显示3个
page_size_query_param = "size"
#最大页数
max_page_size = 10
#获取页码数的
page_query_param = "page"
然后我们在我们之前定义好的Viewsets类下使用它即可
class StudentViewSet(viewsets.ModelViewSet):
# 指定结果集并设置排序
queryset = Student.objects.all().order_by('-pk')
# 指定序列化的类
serializer_class = StudentSerializers
#指定分页配置
pagination_class = PageSet
运行项目查看视图,是不是又变了?
可以看到右上角多了分页的按钮可以进行分页。当然也可以通过URL来进行访问分页后的内容:
http://127.0.0.1:8000/api/student/?page=1
可以看到,返回的结果集也和之前不一样了:
{
"count": 5,
"next": "http://127.0.0.1:8000/api/student/?page=2",
"previous": null,
"results": [
{
"pk": 6,
"name": "煞笔啊",
"sex": "male",
"sid": "0"
},
{
"pk": 4,
"name": "小明",
"sex": "???",
"sid": "113"
},
{
"pk": 3,
"name": "小王八",
"sex": "男",
"sid": "112"
}
]
}
—
count是该资源下的所有资源的数量。
next是下一页的URL,这个非常重要,在许多场景下会使用得到。
previous则是上一页,也是一个重要的功能
results则是我们的结果集了。
这样一来简单的自定义分页就写好了,有的同学可能要问了,在一些特殊的场景下,比如我临时查找的数据为5条而不是默认设置的3条,该怎么查呢?
很简单,我们在URL参数内设置好参数传入即可,如下:
http://127.0.0.1:8000/api/student/?page=1&size=5
这样就可以把size设置为5进行分页查找。是不是很方便?
按照资源对应的位置
我们在其他的场景下,可能会需要访问到,第x个资源的那页,就是按照位置来定位某一页的内容。
比如我们一页设置3个资源,我们需要访问第4个资源的那页,也就是第二页。
这样该如何来写?参考下面代码:
class LimitSet(pagination.LimitOffsetPagination):
# 每页默认几条
default_limit = 3
# 设置传入页码数参数名
page_query_param = "page"
# 设置传入条数参数名
limit_query_param = 'limit'
# 设置传入位置参数名
offset_query_param = 'offset'
# 最大每页显示条数
max_limit = None
使用方法和上一步一样
class StudentViewSet(viewsets.ModelViewSet):
# 指定结果集并设置排序
queryset = Student.objects.all().order_by('-pk')
# 指定序列化的类
serializer_class = StudentSerializers
#指定分页配置
pagination_class = LimitSet
输入URL就按照位置来查询了,比如查询每页3条、第4条的位置所在的分页情况
http://127.0.0.1:8000/api/student/?limit=3&offset=4
常用的分页功能暂时讲到这里吧
搜索功能可以说是当下必备的一个功能了,他用来检索和过滤用户所需要的信息。
搜索的实现方法非常多,REST framework有提供了一个相对比较简洁的搜索功能给我们使用。打开views.py来里的定义好的viewsets类来设置搜索功能吧。
# 记得要导包啊
from rest_framework import viewsets,filters,pagination
class StudentViewSet(viewsets.ModelViewSet):
# 指定结果集并设置排序
queryset = Student.objects.all().order_by('-pk')
# 指定序列化的类
serializer_class = StudentSerializers
# 指定分页配置
pagination_class = LimitSet
# 配置搜索功能
filter_backends = (filters.SearchFilter,)
# 设置搜索的关键字
search_fields = ('=name','sid')
这里指的注意的是,在search_fields这个元组中,我们设置需要过滤的字段分别为姓名name和学号sid。
我们可以发现视图右上角多了一个filter的按钮,点击可以进行搜索
可以说非常贴心了
搜索的URL也很简单。
http://example.com/list/?search=?search=keyword
姓名这样写:=name 表示完全匹配。例如我写小王,只能搜到小王,不能搜到小王八。
http://127.0.0.1:8000/api/student/?search=?search=小王
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"pk": 2,
"name": "小王",
"sex": "女",
"sid": "110"
}
]
}
而学号在不加任何修饰符下,是模糊搜索,只有搜索内容中有相关的字符串都会被抓取出来。下载我们尝试搜索一下学号带有 1 的学生。
http://127.0.0.1:8000/api/student/?search=1
{
"count": 4,
"next": "http://127.0.0.1:8000/api/student/?limit=3&offset=3&search=1",
"previous": null,
"results": [
{
"pk": 4,
"name": "小明",
"sex": "???",
"sid": "113"
},
{
"pk": 3,
"name": "小王八",
"sex": "男",
"sid": "112"
},
{
"pk": 2,
"name": "小王",
"sex": "女",
"sid": "110"
}
]
}
修饰符有以下几种大家根据实际需求来选择使用:
^ :搜索关键字开头的数据
= :完全匹配搜索
@ :全文搜索(目前只支持MySQL)
$ :正则表达式搜索
简单的检索功能介绍就到此为止了。
排序功能在数据量大的情况下便显得非常有用了。我们在第一篇中有提到的默认排序,但是在未来的开发中,还有其他的需求在等着我们。比如拿这个Student类来说,我们需要对学生做排序,让学生以姓名、学号、班级、成绩等熟悉来进行有效的排序。该怎么做?
还是打开views.py下定义好的viewsets类进行添加代码
class StudentViewSet(viewsets.ModelViewSet):
# 指定结果集并设置排序
queryset = Student.objects.all().order_by('-pk')
# 指定序列化的类
serializer_class = StudentSerializers
# 指定分页配置
pagination_class = PageSet
# 配置搜索功能和排序功能
filter_backends = (filters.SearchFilter,filters.OrderingFilter,)
# 设置搜索的关键字
search_fields = ('=name','sid')
# 设置需要被排序的字段
ordering_fields = ('name', 'sid')
注意filter_backends元组下要添加filters.OrderingFilter才能实现排序功能
配置完毕后。我们这边对name和sid两个字段注册了排序的功能,这时就可以通过视图或者URL来进行排序查询了。
http://127.0.0.1:8000/api/student/?ordering=name&size=10
为了方便查看更多结果,这边我们把分页数量的属性设置成10条。
利用学生姓名字段来进行排序,原来默认的是利用主键pk来排序的。
{
"count": 5,
"next": null,
"previous": null,
"results": [
{
"pk": 4,
"name": "小明",
"sex": "???",
"sid": "113"
},
{
"pk": 2,
"name": "小王",
"sex": "女",
"sid": "110"
},
{
"pk": 3,
"name": "小王八",
"sex": "男",
"sid": "112"
},
{
"pk": 1,
"name": "小红",
"sex": "男",
"sid": "111"
},
{
"pk": 6,
"name": "煞笔啊",
"sex": "male",
"sid": "0"
}
]
}
结果出来了,排序分为两种:升序和降序,使用方法就是在字段前面加不加”-“号的区别而已,非常简洁方便。
这已经是第三篇了。还有一些功能下次会继续提出来,比如如何使用api进行多表联查等功能。
其实有了这些功能以及足够搭建一个微小的服务平台了。
接下去有时间我会更新一下实战项目,比如制作一套前后台分离的系统,前台分别用web端和android端来实现。
新手,写的不好,有很多地方的借鉴网上大佬和官方文档的写法。谢谢。