【Python】利用Django搭建REST风格API后台服务(三)关于DRF的搜索、分页、排序

原文地址

简介

这是第三篇内容,接下来我们介绍一下如何使用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

运行项目查看视图,是不是又变了?

image.png

可以看到右上角多了分页的按钮可以进行分页。当然也可以通过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的按钮,点击可以进行搜索

image.png

可以说非常贴心了

image.png

搜索的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来进行排序查询了。

image.png

  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端来实现。

新手,写的不好,有很多地方的借鉴网上大佬和官方文档的写法。谢谢。

猜你喜欢

转载自blog.csdn.net/weixin_40193776/article/details/81221086