在API中添加分页 – Django REST框架
想象一下,你的数据库里有大量的细节。你认为在发出HTTP GET请求时一次性检索所有信息是明智的吗?这就是Django REST框架分页功能的重要性。它有助于将大的结果集分割成每个HTTP请求的单个数据页。
因此,当我们提出HTTP请求时,我们必须指定我们想要检索的具体页面的细节,它将基于预定义的分页方案。除了以页面形式检索数据外,它还在响应部分提供数据总数、下一页和上一页的信息。
- PageNumberPagination
- LimitOffsetPagination
- CursorPagination
注:你可以参考文章中使用的项目的模型、序列化器和视图的可浏览API部分。
PageNumberPagination
PageNumberPagination风格在请求查询参数中接受一个单一的数字页码。要在全局范围内启用这种分页样式,你可以将rest_framework.pagination.PageNumberPagination类设置为DEFAULT_PAGINATION_CLASS,同时根据需要设置PAGE_SIZE。你可以打开settings.py文件,添加以下配置设置。
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 2,
}
你也可以通过覆盖PageNumberPagination类中的属性来修改分页样式。让我们看一下可用的属性。
- django_paginator_class – 默认为django.core.paginator.Paginator。
- page_size – 它表示页面大小(数字值)。如果设置了,它将覆盖PAGE_SIZE设置。默认为与PAGE_SIZE设置键相同的值。
- page_query_param – 分页控件要使用的查询参数名称(字符串值)。
- page_size_query_param – 它表示一个查询参数的名称(字符串值),允许客户在每个请求的基础上设置页面大小。默认为无。
- max_page_size – 它表示最大允许的请求页面大小(数字值)。这个属性只有在page_size_query_param也被设置时才有效。
- last_page_strings – 它与page_query_param一起使用,用于请求集合中的最后一页。默认为(‘last’,)
- template – 在可浏览的API中渲染分页控件时要使用的模板名称。
让我们在数据库中再添加一些机器人的细节。HTTPie的命令是。
http POST :8000/robot/ name=”M-10iD/8L” robot_category=”Articulated Robots” currency=”USD” price=20000 manufacturer=”Fanuc” manufacturing_date=”2020-02-12 00:00:00+00:00″
http POST :8000/robot/ name=”SR-6iA” robot_category=”SCARA Robots” currency=”USD” price=10000 manufacturer=”Fanuc” manufacturing_date=”2020-02-12 00:00:00+00:00″
现在,让我们编写并发送一个HTTP GET请求并分析分页结果。
http :8000/robot/
输出
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 531
Content-Type: application/json
Date: Mon, 01 Feb 2021 05:53:29 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"count": 4,
"next": "http://localhost:8000/robot/?page=2",
"previous": null,
"results": [
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2019-10-12T00:00:00Z",
"name": "FANUC M-710ic/50",
"price": 37000,
"robot_category": "Articulated Robots",
"url": "http://localhost:8000/robot/1/"
},
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "ABB",
"manufacturing_date": "2020-05-10T00:00:00Z",
"name": "IRB 910SC",
"price": 27000,
"robot_category": "SCARA Robots",
"url": "http://localhost:8000/robot/2/"
}
]
}
分享命令提示的截图供你参考。
你可以注意到,响应看起来与之前的HTTP GET请求不同。响应有以下几个键。
- count: 所有页面上的资源总数
- next: 链接到下一页
- previous:链接到上一页
- results: 实例的JSON表示数组。
让我们检索一下第2页的结果。HTTPie的命令是
http :8000/robot/?page=2
输出
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 516
Content-Type: application/json
Date: Mon, 01 Feb 2021 05:52:36 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"count": 4,
"next": null,
"previous": "http://localhost:8000/robot/",
"results": [
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2020-02-12T00:00:00Z",
"name": "M-10iD/8L",
"price": 20000,
"robot_category": "Articulated Robots",
"url": "http://localhost:8000/robot/4/"
},
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2020-02-12T00:00:00Z",
"name": "SR-6iA",
"price": 10000,
"robot_category": "SCARA Robots",
"url": "http://localhost:8000/robot/5/"
}
]
}
分享命令提示的截图
LimitOffsetPagination
在LimitOffsetPagination风格中,客户端包括一个 “limit “和一个 “offset “查询参数。limit表示要返回的最大项目数,与page_size的参数相同。偏移量表示查询的起始位置,与未分页的项目有关。要在全局范围内启用LimitOffsetPagination样式,你可以将rest_framework.pagination.LimitOffsetPagination类__设置为DEFAULT_PAGINATION_CLASS。配置如下。
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 2,
}
你可以跳过设置PAGE_SIZE 。如果设置了,那么客户端就可以省略限制查询参数。
如果你想修改分页样式,你可以覆盖LimitOffsetPagination类的属性。
- default_limit – 它表示(数值)的限制。默认为与PAGE_SIZE设置键相同的值。
- limit_query_param – 它表示 “限制 “查询参数的名称。默认为’limit’。
- offset_query_param – 它表示 “offset “查询参数的名称。默认为’offset’。
- max_limit – 它表示客户端可能请求的最大允许限额。默认为无。
- template – 在可浏览的API中渲染分页控件时使用的模板名称。
HTTPie的命令是
http :8000/robot/
输出
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 541
Content-Type: application/json
Date: Mon, 01 Feb 2021 06:47:42 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"count": 4,
"next": "http://localhost:8000/robot/?limit=2&offset=2",
"previous": null,
"results": [
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2019-10-12T00:00:00Z",
"name": "FANUC M-710ic/50",
"price": 37000,
"robot_category": "Articulated Robots",
"url": "http://localhost:8000/robot/1/"
},
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "ABB",
"manufacturing_date": "2020-05-10T00:00:00Z",
"name": "IRB 910SC",
"price": 27000,
"robot_category": "SCARA Robots",
"url": "http://localhost:8000/robot/2/"
}
]
}
让我们根据上述输出的下一个字段值,尝试另一个HTTPie命令。这条HTTPie命令是
http GET “:8000/robot/?limit=2&offset=2”
输出
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 524
Content-Type: application/json
Date: Mon, 01 Feb 2021 06:52:35 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"count": 4,
"next": null,
"previous": "http://localhost:8000/robot/?limit=2",
"results": [
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2020-02-12T00:00:00Z",
"name": "M-10iD/8L",
"price": 20000,
"robot_category": "Articulated Robots",
"url": "http://localhost:8000/robot/4/"
},
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2020-02-12T00:00:00Z",
"name": "SR-6iA",
"price": 10000,
"robot_category": "SCARA Robots",
"url": "http://localhost:8000/robot/5/"
}
]
}
分享命令提示的截图供你参考
让我们试试limit=1和offset=0,HTTPie的命令是:。
http GET “:8000/robot/?limit=1&offset=0”
输出
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 325
Content-Type: application/json
Date: Mon, 01 Feb 2021 10:36:19 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"count": 4,
"next": "http://localhost:8000/robot/?limit=1&offset=1",
"previous": null,
"results": [
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2019-10-12T00:00:00Z",
"name": "FANUC M-710ic/50",
"price": 37000,
"robot_category": "Articulated Robots",
"url": "http://localhost:8000/robot/1/"
}
]
}
分享命令提示的截图
CursorPagination
CursorPagination提供一个光标指示器来翻阅结果集。它只提供向前或向后的控制,不允许客户端导航到任意的位置。CursorPagination 风格假定在模型实例上必须有一个创建的时间戳字段,并且它按”-创建 “来排列结果。要启用CursorPagination风格,你可以在DEFAULT_PAGINATION_CLASS中提到rest_framework.pagination.CursorPagination类。
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
'PAGE_SIZE': 2,
}
让我们看一下我们可以在CursorPagination类中修改的属性集。它们是如下的。
- page_size – 它表示页面大小(数字值)。默认为与PAGE_SIZE设置键相同的值。
- cursor_query_param – 它表示 “cursor “查询参数的名称(字符串值)。默认为’cursor’。
- ordering – 这应该是一个字符串,或者字符串列表,表明基于游标的分页将被应用的字段。默认值是-created。这个值也可以通过在视图上使用OrderingFilter来重写。
- template – 在可浏览的API中渲染分页控件时要使用的模板名称。
让我们看看如何定制CursorPagination类。这里我们将覆盖排序属性。默认情况下,它将根据创建的时间戳来排序。在这里,我们将使用id字段而不是创建字段来排序。
让我们在应用程序(Robots)文件夹中创建一个名为custompagination.py的新文件,并添加以下代码
from rest_framework.pagination import CursorPagination
class CursorPaginationWithOrdering(CursorPagination):
# order based on id
ordering = 'id'
这里我们覆盖了CursorPagination类所提供的排序属性。接下来,你可以在DEFAULT_PAGINATION_CLASS中提到这个自定义类,如下图所示。
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'robots.custompagination.CursorPaginationWithOrdering',
'PAGE_SIZE': 2,
}
让我们来分析一下输出。你可以发送下面的HTTP命令。
http :8000/robot/
输出
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 526
Content-Type: application/json
Date: Mon, 01 Feb 2021 11:09:45 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"next": "http://localhost:8000/robot/?cursor=cD0y",
"previous": null,
"results": [
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2019-10-12T00:00:00Z",
"name": "FANUC M-710ic/50",
"price": 37000,
"robot_category": "Articulated Robots",
"url": "http://localhost:8000/robot/1/"
},
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "ABB",
"manufacturing_date": "2020-05-10T00:00:00Z",
"name": "IRB 910SC",
"price": 27000,
"robot_category": "SCARA Robots",
"url": "http://localhost:8000/robot/2/"
}
]
}
分享命令提示的截图
现在,让我们根据上面输出的下一个值(cursor=cD0y)来组成一个HTTP请求。HTTPie的命令是
http :8000/robot/?cursor=cD0y
输出
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 530
Content-Type: application/json
Date: Mon, 01 Feb 2021 11:10:38 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"next": null,
"previous": "http://localhost:8000/robot/?cursor=cj0xJnA9NA%3D%3D",
"results": [
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2020-02-12T00:00:00Z",
"name": "M-10iD/8L",
"price": 20000,
"robot_category": "Articulated Robots",
"url": "http://localhost:8000/robot/4/"
},
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2020-02-12T00:00:00Z",
"name": "SR-6iA",
"price": 10000,
"robot_category": "SCARA Robots",
"url": "http://localhost:8000/robot/5/"
}
]
}
分享命令提示的截图