Django(14):分页查询

news/2024/11/27 23:44:53/

使用Django框架内置模块django.core.paginator中封装的Paginator类Page类进行分页功能实现。其中Paginator是分页器,从分页器中可以得到Page,即分页对象。源码如下:

import collections.abc
import inspect
import warnings
from math import ceilfrom django.utils.functional import cached_property
from django.utils.inspect import method_has_no_args
from django.utils.translation import gettext_lazy as _class UnorderedObjectListWarning(RuntimeWarning):passclass InvalidPage(Exception):passclass PageNotAnInteger(InvalidPage):passclass EmptyPage(InvalidPage):passclass Paginator:# Translators: String used to replace omitted page numbers in elided page# range generated by paginators, e.g. [1, 2, '…', 5, 6, 7, '…', 9, 10].ELLIPSIS = _("…")def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):self.object_list = object_listself._check_object_list_is_ordered()self.per_page = int(per_page)self.orphans = int(orphans)self.allow_empty_first_page = allow_empty_first_pagedef __iter__(self):for page_number in self.page_range:yield self.page(page_number)def validate_number(self, number):"""Validate the given 1-based page number."""try:if isinstance(number, float) and not number.is_integer():raise ValueErrornumber = int(number)except (TypeError, ValueError):raise PageNotAnInteger(_("That page number is not an integer"))if number < 1:raise EmptyPage(_("That page number is less than 1"))if number > self.num_pages:if number == 1 and self.allow_empty_first_page:passelse:raise EmptyPage(_("That page contains no results"))return numberdef get_page(self, number):"""Return a valid page, even if the page argument isn't a number or isn'tin range."""try:number = self.validate_number(number)except PageNotAnInteger:number = 1except EmptyPage:number = self.num_pagesreturn self.page(number)def page(self, number):"""Return a Page object for the given 1-based page number."""number = self.validate_number(number)bottom = (number - 1) * self.per_pagetop = bottom + self.per_pageif top + self.orphans >= self.count:top = self.countreturn self._get_page(self.object_list[bottom:top], number, self)def _get_page(self, *args, **kwargs):"""Return an instance of a single page.This hook can be used by subclasses to use an alternative to thestandard :cls:`Page` object."""return Page(*args, **kwargs)@cached_propertydef count(self):"""Return the total number of objects, across all pages."""c = getattr(self.object_list, "count", None)if callable(c) and not inspect.isbuiltin(c) and method_has_no_args(c):return c()return len(self.object_list)@cached_propertydef num_pages(self):"""Return the total number of pages."""if self.count == 0 and not self.allow_empty_first_page:return 0hits = max(1, self.count - self.orphans)return ceil(hits / self.per_page)@propertydef page_range(self):"""Return a 1-based range of pages for iterating through withina template for loop."""return range(1, self.num_pages + 1)def _check_object_list_is_ordered(self):"""Warn if self.object_list is unordered (typically a QuerySet)."""ordered = getattr(self.object_list, "ordered", None)if ordered is not None and not ordered:obj_list_repr = ("{} {}".format(self.object_list.model, self.object_list.__class__.__name__)if hasattr(self.object_list, "model")else "{!r}".format(self.object_list))warnings.warn("Pagination may yield inconsistent results with an unordered ""object_list: {}.".format(obj_list_repr),UnorderedObjectListWarning,stacklevel=3,)def get_elided_page_range(self, number=1, *, on_each_side=3, on_ends=2):"""Return a 1-based range of pages with some values elided.If the page range is larger than a given size, the whole range is notprovided and a compact form is returned instead, e.g. for a paginatorwith 50 pages, if page 43 were the current page, the output, with thedefault arguments, would be:1, 2, …, 40, 41, 42, 43, 44, 45, 46, …, 49, 50."""number = self.validate_number(number)if self.num_pages <= (on_each_side + on_ends) * 2:yield from self.page_rangereturnif number > (1 + on_each_side + on_ends) + 1:yield from range(1, on_ends + 1)yield self.ELLIPSISyield from range(number - on_each_side, number + 1)else:yield from range(1, number + 1)if number < (self.num_pages - on_each_side - on_ends) - 1:yield from range(number + 1, number + on_each_side + 1)yield self.ELLIPSISyield from range(self.num_pages - on_ends + 1, self.num_pages + 1)else:yield from range(number + 1, self.num_pages + 1)class Page(collections.abc.Sequence):def __init__(self, object_list, number, paginator):self.object_list = object_listself.number = numberself.paginator = paginatordef __repr__(self):return "<Page %s of %s>" % (self.number, self.paginator.num_pages)def __len__(self):return len(self.object_list)def __getitem__(self, index):if not isinstance(index, (int, slice)):raise TypeError("Page indices must be integers or slices, not %s."% type(index).__name__)# The object_list is converted to a list so that if it was a QuerySet# it won't be a database hit per __getitem__.if not isinstance(self.object_list, list):self.object_list = list(self.object_list)return self.object_list[index]def has_next(self):return self.number < self.paginator.num_pagesdef has_previous(self):return self.number > 1def has_other_pages(self):return self.has_previous() or self.has_next()def next_page_number(self):return self.paginator.validate_number(self.number + 1)def previous_page_number(self):return self.paginator.validate_number(self.number - 1)def start_index(self):"""Return the 1-based index of the first object on this page,relative to total objects in the paginator."""# Special case, return zero if no items.if self.paginator.count == 0:return 0return (self.paginator.per_page * (self.number - 1)) + 1def end_index(self):"""Return the 1-based index of the last object on this page,relative to total objects found (hits)."""# Special case for the last page because there can be orphans.if self.number == self.paginator.num_pages:return self.paginator.countreturn self.number * self.paginator.per_page

从源码也可以看出,Paginator对象的主要属性和方法:

  1. object_list:当前分页对象所有的数据列表。
  2. per_page:分页对象的每页的展示的对象的数量。
  3. orphans:如果分页的页数的数据总记录数不匹配,会导致最后一页显示少量数据。该属性控制是否将最后一页的数据添加到上一页展示。比如,总记录数为23,每页展示10条数据,正常最后一页会只展示3条数据。但是如果设置orphans=5,因为最后一页数量3小于5,则会把最后一页数据展示到上一页。
  4. allow_empty_first_page:如果分页查询数据为空,如果该属性为False,则第一页是否以空白页展示,并抛出EmptyPage异常。默认为True,不抛异常。
  5. get_page(number):获取第number页的分页对象,即返回Page对象。
  6. count():获取数据的总记录数。
  7. num_pages():获取分页的总页数。
  8. page_range():获取分页对象的range(1, n)生成器。
  9. EmptyPage:如果在分页操作中,出现页码对应的查询数据不存在,则抛出EmptyPage异常。

Page对象的主要属性和方法:

  1. has_next():当前页后面是否有下一页
  2. has_previous():当前页前面是否有前一页
  3. has_other_pages:当前页是否还有其他页,has_next和has_previous满足其一返回True
  4. next_page_number():返回下一页的页码
  5. previous_page_number():返回上一页的页码
  6. start_index():获取当前页面中起始数据的索引编号。比如每页10条数据,第2页就返回10 * (2 - 1) + 1 = 11。
  7. end_index():获取当前页面中结束数据的索引编号。

示例:

def list(request):# 通过ORM查询对象的所有数据user_list = User.objects().all()# 构建Paginator对象,每页20条数据paginator = Paginator(user_list, 20)# 获取当前页码page = request.GET.get('page')if page is None:page = 1# 从分页对象中获取页码对象users = paginator.get_page(page)return render(request, 'list.html', {'users': users})

http://www.ppmy.cn/news/10894.html

相关文章

接口测试——postman和Jemter

接口测试——postman和Jemterpostmanpostman工作原理postman入门postman的基础用法postman的高级用法使用postman管理测试用例批量执行测试用例postman断言环境变量和全局变量postman关联postman请求前置脚本postman参数化及生成测试报告参数化与数据驱动postman生成测试报告je…

JDK并发编程Actomic和AQS详解

JDK并发编程Actomic和AQS详解1 Atomic系列优化加锁并发性能1.0 i和ActomicInteger之间的差别分析1.1 AtomicInteger中的CAS无锁化原理1.2 AtomicInteger源码剖析&#xff1a;仅限JDK内部使用的Unsafe类1.3 AtomicInteger源码剖析&#xff1a;无线重复循环以及CAS操作1.4 Atomic…

Kubernetes(k8s) 笔记总结(二)

提示&#xff1a;针对kubernetes的工作均衡学习。 文章目录1. Kubernetes 创建资源方式2. Kubernetes 操作NameSpace3. Kubernetes的 Pod应用3.1 Pod的 解释3.2 通过命令行来创建一个pod3.3 配置文件方式创建一个Pod3.4 dashboard 可视化操作Pod3.5 针对Pod的一些细节操作3.6 P…

基于 js 制作一个贪吃蛇小游戏

目录前言&#xff1a;项目效果展示&#xff1a;代码实现思路&#xff1a;使用方法&#xff1a;实现代码&#xff1a;总结&#xff1a;前言&#xff1a; 在工作学习之余玩一会游戏既能带来快乐&#xff0c;还能缓解生活压力&#xff0c;跟随此文一起制作一个小游戏吧。 描述&…

Java日期时间类

Java日期时间类Datenew Date()**获取当前系统时间**通过**指定毫秒数得到时间**format**指定日期格式**SimpleDateFormat的模式字母&#xff1a;parse()可以把**格式化的String转成对应Date**Calendar&#xff08;日历&#xff09;创建日期类对象获取日历对象的某个日历字段第三…

IPO合肥马郢计划:构筑美丽田园综合体上市

合肥市长丰县马郢社区曾经是省级贫困村&#xff0c;为了让这个原本相对落后美丽田园 上市拥有崭新的面貌。2017年至今实施美丽田园综合体、旅游扶贫等项目。马郢社区共有13个村民组、408户、1778人&#xff0c;全村建档立卡贫困户年人均收入仅2000多元。2015年&#xff0c;由杨…

python制作课堂点名系统,从此老师对我关爱有加

前言 大家早好、午好、晚好吖 ❤ ~ 准备工作 首先我们需要准备好点名的姓名文件&#xff0c;使用的时候导入进去就可以开始点名了。 新建一个文本文档&#xff0c;将姓名设置设置好&#xff0c;如下&#xff1a; 使用系统库和第三方库都比较常规 from PyQt5.QtWidgets impo…

【Java编程进阶】Java异常详解

推荐学习专栏&#xff1a;Java 编程进阶之路【从入门到精通】&#xff0c;从入门到就业精通&#xff0c;买不了吃亏&#xff0c;买不了上当&#xff01;&#xff01; 文章目录1. 异常2. 异常的体系3. Error4. 异常产生的过程5. throw 关键字6. 异常处理6.1 throws 关键字6.2 tr…