3

Django笔记三十四之分页操作 - XHunter

 1 year ago
source link: https://www.cnblogs.com/hunterxiong/p/17364803.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文首发于公众号:Hunter后端

原文链接:Django笔记三十四之分页操作

这一篇笔记介绍一下如何在 Django 使用分页。

Django 自带一个分页的模块:

from django.core.paginator import Paginator

主要用途是列表数据的切割,比如说有 3000 条用户数据,前端需要一个列表接口用于展示这些数据,但是一次性展现这么多数据不合适,所以打算用分页的方式来操作。

比如一页20条数据,前端通过按钮控制 page_num 和 size 参数用于后端返回数据。

以下是本篇笔记目录:

  1. 直接分页操作
  2. Paginator 分页操作
  3. Paginator 其他函数
  4. Page 的其他操作

1、直接分页操作

在介绍 Django 的分页模块前,我们一般如果要分页的话会如何操作呢,这里我们定义 page_num 参数为 页数,size 参数为一页返回的数据量。

假设有这样一个长度为 20 的列表:

data_list = list(range(20))

我们想要实现每页三条数据,也就是 size = 3,我们根据 page_num 和 size 参数可以这样操作:

target_list = data_list[(page_num - 1) * size: page_num * size]

因为页数是从 1 开始的,而列表的下标是从 0 开始的,所以这里是 page_num - 1。

以这个为例,我们接下来介绍一下如何使用 Django 的模块来操作分页。

2、Paginator 分页操作

Paginator 不仅可以用于 model 的 queryset 数据,也可以用于我们上面这种列表数据 data_list,我们这里使用 data_list 作为示例。

以下是一个简单的使用 Paginator 的示例:

from django.core.paginator import Paginator

data_list = list(range(20))
page_num = 1
size = 3

paginator = Paginator(data_list, size)

target_page_data = paginator.page(page_num)
# <Page 1 of 7>

for item in target_page_data:
    print(item)
    
count = paginator.count

在上面的示例中,Paginator() 方法接收需要分页的可迭代数据,可以是这里的列表,也可以是 Django 里的 QuerySet 类型,然后通过 .page() 函数指定 page_num 数就可以获取指定页数的数据。

另外,如果需要获取总数,可以直接 .count 获取接收的可迭代数据的总数。

分页超出总页数

比如前面我们根据 size 大小对数据进行了分页,最多只能分为 7 页,但是后面我们的 page 数传入的是 7,会怎么办呢?会报错:

    raise EmptyPage(_('That page contains no results'))
django.core.paginator.EmptyPage: That page contains no results

如何规避这种情况呢,当然,前端在传入的时候可以做一定的限制,但是后端也要有这样的控制,可以在传入 page_num 参数前就对数据做一个校验,发现 page_num 超出总页数则直接 raise 报错返回前端,或者直接传入 page_num,通过 try except 来控制,发现报错的话,直接返回空列表,比如:

data_list = list(range(20))
page_num = 10
size = 3

paginator = Paginator(data_list, size)

try:
    target_page_data = paginator.page(page_num)
except:
    target_page_data = []
    
count = paginator.count

3、Paginator 其他函数

get_page(number)

前面我们对于每页数据的获取有一个 try except 的操作:

try:
    target_page_data = paginator.page(page_num)
except:
    target_page_data = []

假设说我们的数据只能分 7 页数据,那么 paginator.page(page_num) 的 page_num 参数就只能在 1-7 之间,可以是 int,也可以是字符串的 1-7,比如 "2",除此之外输入的其他参数,比如 0, -1,或者其他非法字符串都会引发报错。

所以我们使用了一个 try except 操作来捕获异常,当发生异常时,我们返回的是空列表。

get_page() 函数相当于是基于 page() 函数做了异常处理,当我们输入的数据是非法整数时,比如页数在 1-7 之间,我们输入的是 0,或者 -1,或者 10,返回的则是最后一页数据:

>>> paginator.get_page(99)
<Page 7 of 7>

如果我们输入的是其他的非法数据的时候,返回的则是第一页数据:

>>> paginator.get_page('a')
<Page 1 of 7>

count 属性

前面介绍了,可以通过 paginator.count 的方式来拿到待分页的数据的总数,这里介绍一下 .count 实现的方式。

因为 Paginator 是既可以对列表类型数据进行分页,也可以对 QuerySet 进行分页,但是 QuerySet 有 .count() 函数,而列表数据是没有这个操作的。

但是如果统一都用 len() 函数来对输入的数据进行取长度,这又是不现实的,因为 len() 函数的操作流程会将 QuerySet 数据都加载然后取值,在 QuerySet 无比大的时候这又是不现实的,这一点在之前的 Django 查询优化笔记中有记录。

所以这里的 count 背后的方法是先去查看这个数据有没有 count() 方法,有的话就执行,比如一个 QuerySet,没有的话就执行 len() 函数,比如列表数据。

num_pages 属性

返回总页数,比如我们前面的示例返回的数据是 7:

paginator.num_pages
# 7

page_range 属性

返回页数范围,是一个 range() 类型:

paginator.page_range

4、Page 的其他操作

这里的 Page 指的是分页后的一页数据的 Page 类型,也就是前面我们定义的 target_page_data 数据:

target_page_data = paginator.page(page_num)

是否有前一页

>>> target_page_data.has_previous()
# True

是否有后一页

>>> target_page_data.has_next()
# True

获取下一页的页数

>>> target_page_data.next_page_number()
# 2

获取前一页的页数

target_page_data.next_page_number()

注意:如果当前页在第一页或者最后一页,当我们使用获取前一页或者下一页的页数时会报错。

当前页的开始和结束索引

对于某页数据,如果想获取该页数据在全部数据中的索引,比如说,对于一个长度为 20 的列表进行分页,每页数量为 4,获取的是第 1 页的数据,那么这页数据的开始和结束索引就在 1 和 4,因为这里定义的索引是从 1 开始计算的。

>>> target_page_data = paginator.page(1)
>>> 
>>> target_page_data.start_index()
# 1
>>> target_page_data.end_index()
# 4

当前页数

获取当前页数:

target_page_data.number

获取当前页数据列表

>>> target_page_data.object_list
[12, 13, 14]

如果想获取更多后端相关文章,可扫码关注阅读:

image

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK