django写博客第八章

1 分页器的原理和使用
2 Django自身提供了一些类来实现管理分页,数据被分在不同的页面中,并带有“上一页/下一页”标签。这个类叫做Pagination,其定义位于 django/core/paginator.py 中。
3 源码分析

class Paginator:

    def __init__(self, object_list, per_page, orphans=0,
                 allow_empty_first_page=True):
        # object_listt:可以是列表,元组,查询集或其他含有 count() 或 __len__()方法的可切片对     象。对于连续的分页,查询集应该有序,例如有order_by()项或默认ordering参数。
        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  # 如果它是浮点数或者不是整数就会抛出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):# 这里要注意,当调用这个page时,会返回self._get_page(),当调用
    self._get_page()时,会返回Page(*args, **kwargs),,这样也就意味着page(p是小写)的返回值是一个Page对象(P是大写),就能调用该对象的相应的方法
        """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."""
        try:
            return self.object_list.count()
        except (AttributeError, TypeError):
            # AttributeError if object_list has no count() method.
            # TypeError if object_list.count() requires arguments
            # (i.e. is of type list).
            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
            )


QuerySetPaginator = Paginator   # For backwards-compatibility.


class Page(collections.abc.Sequence):  这个类同样很重要
它继承了collections.abc.Sequence这个东西,这个东西我还不太理解,不过不妨碍我对源码的理解

    def __init__(self, object_list, number, paginator):
        self.object_list = object_list
        self.number = number
        self.paginator = paginator # Paginator对象

    def __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
        # 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):  #  如果有下一页,则返回True
        return self.number < self.paginator.num_pages 如果还有下一页就肯定小于总的啊,就一定会返回True

    def has_previous(self): #如果·有上一页,就一定大于1啊,也就是要返回True
        return self.number > 1

    def has_other_pages(self):#如果有上一页或者下一页,就返回True
        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 0
        return (self.paginator.per_page * (self.number - 1)) + 1

    def 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.count
        return self.number * self.paginator.per_page

总结一下:
Paginator类
object_list:可以是列表,元组,查询集或其他含有 count() 或 _len_()方法的可切片对象。对于连续的分页,查询集应该有序,例如有order_by()项或默认ordering参数。
per_page:每一页中包含条目数目的最大值,不包括独立成页的那页。(见下面 orphans参数解释)
orphans=0:当你使用此参数时说明你不希望最后一页只有很少的条目。如果最后一页的条目数少于等于orphans值,则这些条目会被归并到上一页中(此时的上一页变为最后一页)。例如有23项条目, per_page=10,orphans=0,则有3页,分别为10,10,3.如果orphans>=3,则为2页,分别为10,13。**
allow_empty_first_page=True: 默认允许第一页为空。
.类方法:
* Paginator.page(number):根据参数number返回一个Page对象。(number为1的倍数)*
.类属型:
Paginator.count:所有页面对象总数,即统计object_list中item数目。当计算object_list所含对象的数量时, Paginator会首先尝试调用object_list.count()。如果object_list没有 count() 方法,Paginator 接着会回退使用len(object_list)。
Pagnator.num_pages:页面总数。
pagiator.page_range:页面范围,从1开始,例如[1,2,3,4]。

Page类:
Page.has_next() 如果有下一页,则返回True。
Page.has_previous() 如果有上一页,返回 True。
Page.has_other_pages() 如果有上一页或下一页,返回True。
Page.next_page_number() 返回下一页的页码。如果下一页不存在,抛出InvlidPage异常。
Page.previous_page_number() 返回上一页的页码。如果上一页不存在,抛出InvalidPage异常。
Page.start_index() 返回当前页上的第一个对象,相对于分页列表的所有对象的序号,从1开始。比如,将五个对象的列表分为每页两个对象,第二页的start_index()会返回3。
Page.end_index() 返回当前页上的最后一个对象,相对于分页列表的所有对象的序号,从1开始。 比如,将五个对象的列表分为每页两个对象,第二页的end_index() 会返回 4。
2.类属型

Page.object_list 当前页上所有对象的列表。
Page.number 当前页的序号,从1开始。
Page.paginator 相关的Paginator对象。

异常处理:
InvalidPage(Exception): 异常的基类,当paginator传入一个无效的页码时抛出。
Paginator.page()放回在所请求的页面无效(比如不是一个整数)时,或者不包含任何对象时抛出异常。通常,捕获****InvalidPage异常就够了,但是如果你想更加精细一些,可以捕获以下两个异常之一:

exception PageNotAnInteger,当向page()提供一个不是整数的值时抛出。
exception EmptyPage,当向page()提供一个有效值,但是那个页面上没有任何对象时抛出。
这两个异常都是InalidPage的子类,所以可以通过简单的except InvalidPage来处理它们。

不足之处,欢迎批评指正,thanks!

参考链接*https://www.cnblogs.com/king-lps/p/7324821.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值