django分页Paginator的简单使用

2021年09月15日 阅读数:4
这篇文章主要向大家介绍django分页Paginator的简单使用,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

以前同事在项目中写了分页的一个函数,可是并无返回结果集的总个数和总页数。因此我就想到了用 django 自带的分页类获取分页的数据。由于要分页的对象多是个列表而不是 django 模型的查询集。只是使用了Paginator类查看总页数和总个数的方法。python

from django.core.paginator import Paginatorpage_rows= "每页展现多少条数据"# 注queryset是一个模型的查询集p= Paginator(queryset, page_rows)# 获取查询集的总个数total_count= p.count# 获取查询集的总页数total_page= p.num_pages

Paginator类源码数据库

class Paginator:
def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True): self.object_list = object_list self._check_object_list_is_ordered() self.per_page = int(per_page) self.orphans = int(orphans) self.allow_empty_first_page = allow_empty_first_page
def validate_number(self, number): """Validate the given 1-based page number.""" try: if isinstance(number, float) and not number.is_integer(): raise ValueError number = 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: pass else: raise EmptyPage(_('That page contains no results')) return number
def get_page(self, number): """ Return a valid page, even if the page argument isn't a number or isn't in range. """ try: number = self.validate_number(number) except PageNotAnInteger: number = 1 except EmptyPage: number = self.num_pages return 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_page top = bottom + self.per_page if top + self.orphans >= self.count: top = self.count return 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 the standard :cls:`Page` object. """ return Page(*args, **kwargs)
@cached_property def 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_property def num_pages(self): """Return the total number of pages.""" if self.count == 0 and not self.allow_empty_first_page: return 0 hits = max(1, self.count - self.orphans) return ceil(hits / self.per_page)
@property def page_range(self): """ Return a 1-based range of pages for iterating through within a 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 )

我自定义个人分页函数只是用了 count 和 num_pages 方法,由于我初始化 Paginator 时传入的 queryset 没有进行排序,就触发了 _check_object_list_is_ordered方法的警告。官方的解释是  【A list, tuple, QuerySet, or other sliceable object with a count() or __len__() method. For consistent pagination, QuerySets should be ordered, e.g. with an order_by() clause or with a default ordering on the model】.在一个 qq 群里有人给我解释分页必需要保证幂等,换句话说是我第一页的内容无论查多少次,都是第一页的内容。在这种状况下幂等是交由  order_by  的数据来保证的,在常见数据库中,保持一个序列顺序固定,是须要显示的 order by 来作,虽然咱们查询的时候,默认会根据自增 ID 来作一次 order by,可是这是一个不可靠行为,或者说是叫作 undefined behavior ,Django 为了保证在不一样数据库,不一样版本的数据库中数据一致,加上了这样一个强制。django

我还想说一句,num_pages 方法中的ceil函数使用让我眼前一亮,之前求总页数我都是用数学运算分好几种状况考虑,可是看了源码,让人眼前一亮,真的很厉害!微信

def ceil(*args, **kwargs): # real signature unknown    """    Return the ceiling of x as an Integral.        This is the smallest integer >= x.    """    pass


本文分享自微信公众号 - pythonista的平常(gh_fc70d5d98d3f)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。app