专栏首页pythonista的日常django分页Paginator的简单使用

django分页Paginator的简单使用

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

from django.core.paginator import Paginator
page_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 为了保证在不同数据库,不同版本的数据库中数据一致,加上了这样一个强制。

我还想说一句,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),作者:pythonista

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python 操作 redis 的一些例子

    主要是介绍 python 操作 redis 的有序集合,以及使用 redis 实现分布式锁的功能。

    用户4945346
  • Django REST framework初识

    现在工作中用的就是 django-rest 框架,今天主要讲下 django-rest 是个什么东西,为什么会使用它。准确的说 django-rest 是 dj...

    用户4945346
  • django2.2+Daphne+nginx+supervisor 生产环境部署

    之前项目中使用了 webscoket 进行实现消息实时通知,我们是另外单独运行了一个消息推送服务项目,使用了django-channels 实现websocke...

    用户4945346
  • 一篇文章教会你用Python多线程获取小米应用商店App

    小米应用商店给用户发现最好的安卓应用和游戏,安全可靠,可是要下载东西要一个一个的搜索太麻烦了。而已速度不是很快。

    Python进阶者
  • Quartz2D复习(二) --- 手势解锁

    这次支付宝手机客户端升级,把手势解锁那个功能去掉了,引起很多人的抱怨,觉得少了手势解锁的保护,个人信息容易泄漏了。。。

    tandaxia
  • 实践-小效果 Ⅳ

    设置一个UIImageView为倒立的同等控件,设置这个UIImageView的layer的mask为一个渐变图层,效果就出来了。

    進无尽
  • 原创 | 你会用缓存吗?详解LRU缓存淘汰算法

    大家好,欢迎大家来到周三算法数据结构专题,今天我们和大家聊一个非常常用的算法,叫做LRU。

    TechFlow-承志
  • iOS 开发之路(使用WKWebView加载Html5) 四

      基于Swift 3 、 Xcode 8 、 iOS 10 下的WKWebView的使用。

    从今若
  • 【基础详解】手磕实现 CNN卷积神经网络!

    链接:https://blog.csdn.net/Walk_OnTheRoad/article/details/108048101

    zenRRan
  • TensorFlow强化学习入门(4)——深度Q网络(DQN)及其扩展

    本文中我们将一起创建一个深度Q网络(DQN)。它基于我们系列文章中(0)的单层Q网络,如果你是强化学习的初学者,我推荐你到文末跳转到(0)开始阅读。尽管简单的Q...

    ArrayZoneYour

扫码关注云+社区

领取腾讯云代金券