Django之分页器

Django自带分页器的实现

介绍

Django提供了一个新的类来帮助你管理分页数据,这个模块存放在django.core.paginator.py。
其中有两个核心类,一个是Paginator类,另一个是Page类。

Paginator类
初始化操作
class Paginator(object):
    def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):
        self.object_list = object_list
        self.per_page = int(per_page)
        self.orphans = int(orphans)
        self.allow_empty_first_page = allow_empty_first_page
        self._num_pages = self._count = None

解释:

  • object_list:可以是列表,元组,查询集或其他含有 count() 或 len()方法的可切片对象。对于连续的分页,查询集应该有序,例如有order_by()项或默认ordering参数。
  • per_page:每一页中包含条目数目的最大值,不包括独立成页的那页。(见下面 orphans参数解释)。
  • orphans=0:当你使用此参数时说明你不希望最后一页只有很少的条目。如果最后一页的条目数少于等于orphans的值,则这些条目会被归并到上一页中(此时的上一页变为最后一页)。
  • 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类
初始化操作
class Page(collections.Sequence):
    def __init__(self, object_list, number, paginator):
        self.object_list = object_list
        self.number = number
        self.paginator = paginator
类方法
  • 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。
类属型
  • Page.object_list 当前页上所有对象的列表。
  • Page.number 当前页的序号,从1开始。
  • Page.paginator 相关的Paginator对象。
异常处理
  • InvalidPage(Exception): 异常的基类,当paginator传入一个无效的页码时抛出。
    Paginator.page()放回在所请求的页面无效(比如不是一个整数)时,或者不包含任何对象时抛出异常。通常,捕获InvalidPage异常就够了,但是如果你想更加精细一些,可以捕获以下两个异常之一:
  • exception PageNotAnInteger,当向page()提供一个不是整数的值时抛出。
    exception EmptyPage,当向page()提供一个有效值,但是那个页面上没有任何对象时抛出。
    这两个异常都是InalidPage的子类,所以可以通过简单的except InvalidPage来处理它们。
使用方式
  • views.py
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render

def listing(request):
    contact_list = Contacts.objects.all()  # 获取所有contacts,假设在models.py中已定义了Contacts模型
    paginator = Paginator(contact_list, 25) # 每页25条
    page = request.GET.get('page')
    try:
        contacts = paginator.page(page) # contacts为Page对象!
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        contacts = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        contacts = paginator.page(paginator.num_pages)
    return render(request, 'list.html', {'contacts': contacts})
  • *.html
{% for contact in contacts %}
    {# Each "contact" is a Contact model object. #}
    {{ contact.full_name|upper }}
... {% endfor %}

或者另一种形式


存在问题
描述

上面这种分页方式,在数据量较小的时候是没有效率问题,但是随着数据量的不断增大,查询速度越来越慢。


Django分页器优化的实现

原理

利用Django查询集的惰性查询特性

实现
def owner_page(request, obj):
    """
    # 自定义分页器
    :param request: request请求
    :param obj: 分页对象
    :return: 所在页码的对象集,所有页码,当前页码,分页对象的总数
    """
    current_page = 1
    all_page = 1
    page_type = ''
    try:
        current_page = int(request.GET.get('cur', '1'))
        all_page = int(request.GET.get('all', '1'))
        page_type = str(request.GET.get('action', ''))  # 向前翻页还是向下翻页
    except ValueError:
        current_page = 1
        all_page = 1
        page_type = ''

    if page_type == 'next':
        current_page += 1
    elif page_type == 'previous':
        current_page -= 1
    if isinstance(obj, list):
        count = len(obj)
    else:
        count = obj.count()
    start = (current_page - 1) * PAGE_SIZE
    end = current_page * PAGE_SIZE
    data = obj[start:end]

    if current_page == 1 and current_page == 1:  # 标记1
        all_page = math.ceil(count / PAGE_SIZE)
    return data, all_page, current_page, count
使用方式
  • views.py
def get_all_goods(request):
    user_id = request.session.get('user_id')
    goods = Good.objects.get_user_goods(user_id=user_id)
    data, all_page, current_page, count = owner_page(request, goods)
    return render(
        request,
        "goods_all_list.html",
        {'data': data, 'allPage': all_page, 'curPage': current_page, 'count': count}
    )
  • page.html
  • goods_all_list.html
...
{% include "page.html" %}
...

你可能感兴趣的:(Django之分页器)