python_django_Pagination

本文介绍了一种处理大数据量查询的策略——分页查询,通过分批次处理数据避免服务器资源耗尽,提高用户体验。以Django的Paginator为例,展示了如何在视图中实现分页,并提供了代码示例。

分页查询

当数据量过大时,可能会导致各种各样的问题发生,例如:服务器资源被耗尽,因数据传输量过大而使处理超时,等等。最终都会导致查询无法完成。
解决这个问题的一个策略就是“分页查询”,也就是说不要一次性查询所有的数据,每次只查询一“页“的数据。这样分批次地进行处理,可以呈现出很好的用户体验,对服务器资源的消耗也不大。

打一个比方,有很多很多人要过河,而只有一条船摆渡。若让所有人都上船,肯定会导致沉船(资源耗尽);若换一条超大的船,除了换船要很高的成本外,上船下船也要耗费很长时间。
所以最好的解决方法是,根据船的容量,每次只上一部分人。等这一船人过河以后,再摆渡下一批人。


 

Django provides a few classes that help you manage paginated data – that is, data that’s split across several pages, with “Previous/Next” links. These classes live in django/core/paginator.py.

Example

Give Paginator a list of objects, plus the number of items you’d like to have on each page, and it gives you methods for accessing the items for each page:

from django.core.paginator import Paginator
>>> objects = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(objects, 2)

>>> p.count
4
>>> p.num_pages
2
>>> type(p.page_range)  # `<type 'rangeiterator'>` in Python 2.
<class 'range_iterator'>
>>> p.page_range
range(1, 3)

>>> page1 = p.page(1)
>>> page1
<Page 1 of 2>
>>> page1.object_list
['john', 'paul']

>>> page2 = p.page(2)
>>> page2.object_list
['george', 'ringo']
>>> page2.has_next()
False
>>> page2.has_previous()
True
>>> page2.has_other_pages()
True
>>> page2.next_page_number()
Traceback (most recent call last):
...
EmptyPage: That page contains no results
>>> page2.previous_page_number()
1
>>> page2.start_index() # The 1-based index of the first item on this page
3
>>> page2.end_index() # The 1-based index of the last item on this page
4

>>> p.page(0)
Traceback (most recent call last):
...
EmptyPage: That page number is less than 1
>>> p.page(3)
Traceback (most recent call last):
...
EmptyPage: That page contains no results

 

请注意,可以给paginator一个列表/元组、一个django查询集或任何其他带有count()或uu len_uuu()方法的对象。当确定传递对象中包含的对象数时,paginator将首先尝试调用count(),如果传递的对象没有count()方法,则返回到使用len()。这允许Django的queryset等对象在可用时使用更有效的count()方法。

 

Using Paginator in a view

下面是一个稍微复杂一些的例子,在视图中使用paginator来对查询集分页。我们提供视图和附带的模板来显示如何显示结果。此示例假定您有一个已导入的联系人模型。

View函数如下所示:

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render

def listing(request):
    contact_list = Contacts.objects.all()
    paginator = Paginator(contact_list, 25) # Show 25 contacts per page

    page = request.GET.get('page')
    try:
        contacts = paginator.page(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})

 

In the template list.html, you’ll want to include navigation between pages along with any interesting information from the objects themselves:

 

{% for contact in contacts %}
    {# Each "contact" is a Contact model object. #}
    {{ contact.full_name|upper }}<br />
    ...
{% endfor %}

<div class="pagination">
    <span class="step-links">
        {% if contacts.has_previous %}
            <a href="?page={{ contacts.previous_page_number }}">previous</a>
        {% endif %}

        <span class="current">
            Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
        </span>

        {% if contacts.has_next %}
            <a href="?page={{ contacts.next_page_number }}">next</a>
        {% endif %}
    </span>
</div>

 

 

Paginator objects

The Paginator class has this constructor:

class Paginator(object_listper_pageorphans=0allow_empty_first_page=True)[source]

Required argument

object_list

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.

-------

Performance issues paginating large QuerySets
If you’re using a QuerySet with a very large number of items, requesting high page numbers might be slow on some databases, because the resulting LIMIT/OFFSET query needs to count the number of OFFSET records which takes longer as the page number gets higher.

per_page
The maximum number of items to include on a page, not including orphans (see the orphans optional argument below).


Optional arguments

orphans
The minimum number of items allowed on the last page, defaults to zero. Use this when you don’t want to have a last page with very few items. If the last page would normally have a number of items less than or equal to orphans, then those items will be added to the previous page (which becomes the last page) instead of leaving the items on a page by themselves. For example, with 23 items, per_page=10, and orphans=3, there will be two pages; the first page with 10 items and the second (and last) page with 13 items.

allow_empty_first_page

Whether or not the first page is allowed to be empty. If False and object_list is empty, then an EmptyPage error will be raised.

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值