O Django fornece algumas classes que ajudam a lidar com paginação de dados – isto é, dados que são divididos entre várias páginas, com links “Previous/Next”. Essas classes estão contidas no módulo django/core/paginator.py.
Dada a um Paginator uma lista de objetos, mais um número de itens que você gostaria que aparececem em cada página, ele fornecerá os métodos necessários para acessar os itens de cada página:
>>> from django.core.paginator import Paginator
>>> objects = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(objects, 2)
>>> p.count
4
>>> p.num_pages
2
>>> p.page_range
[1, 2]
>>> 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()
3
>>> page2.previous_page_number()
1
>>> page2.start_index() # O índice iniciado em 1 do primeiro item nesta página
3
>>> page2.end_index() # O índice iniciado em 1 do último item nesta página
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
Note
Note que você pode dar a um paginador uma lista ou tupla Paginator, uma QuerySet do Django, ou qualquer objeto com um método count() ou __len__(). Ao determinar o número de objetos contidos no objeto passado, o Paginator vai primeiro tentar chamar count(), depois irá tentar chamar len() se o objeto não tiver um método count(). Isso permite a objetos como o QuerySet do Django usarem um count() mais eficiente, quando disponível.
Aqui há um exemplo ligeiramente mais complexo do uso do Paginator em um view para paginar um queryset. Nós dizemos a ambos, view e o template que o acompanha, como você pode exibir resultados. Este exemplo assume que você tem um model Contacts que já foi importado.
A função view parece com isso:
from django.core.paginator import Paginator, InvalidPage, EmptyPage
def listing(request):
contact_list = Contacts.objects.all()
paginator = Paginator(contact_list, 25) # Mostra 25 contatos por página
# Make sure page request is an int. If not, deliver first page.
# Esteja certo de que o `page request` é um inteiro. Se não, mostre a primeira página.
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
# Se o page request (9999) está fora da lista, mostre a última página.
try:
contacts = paginator.page(page)
except (EmptyPage, InvalidPage):
contacts = paginator.page(paginator.num_pages)
return render_to_response('list.html', {"contacts": contacts})
No template list.html, você poderá incluir a navegação entre as páginas, juntamente com qualquer informação interessante a partir dos próprios objetos:
{% for contact in contacts.object_list %}
{# Cada "contato" é um objeto do model Contact. #}
{{ contact.full_name|upper }}<br />
...
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if contacts.has_previous %}
<a href="?page={{ contacts.previous_page_number }}">anterior</a>
{% endif %}
<span class="current">
Página {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
</span>
{% if contacts.has_next %}
<a href="?page={{ contacts.next_page_number }}">próxima</a>
{% endif %}
</span>
</div>
A classe Paginator tem este construtor:
Retorna um objeto Page com um determinado índice. Se a determinada página não existe, é lançado uma exceção InvalidPage.
O número total de objetos, através de todas as páginas.
Note
Quando se determina o número de objetos contidos no object_list, o Paginator irá primeiro tentar chamar object_list.count(). Se object_list não tem o método count(), então o Paginator tentará usar o object_list.__len__(). Isto permite objetos, como um QuerySet do Django, usar um método de count() mais eficiente quando disponível.
O número total de páginas.
Um número começando com 1 de páginas, por exemplo, [1, 2, 3, 4].
O método page() lança a exceção InvalidPage se a página requisitada for inválida (ex., não for um inteiro) ou não conter objetos. Geralmente, isto é suficiente para se ter uma exceção InvalidPage, mas se você quizer mais granularidade, você pode utilizar qualquer uma dessas exceções:
Ambas as exceções são subclasses de InvalidPage, então você poder manipulá-las com um simples except InvalidPage.
Você normalmente não iŕa construir Pages na mão -- você vai obtê-los usando Paginator.page().
Retorna True se existe uma página subseqüente.
Retorna True se existe uma página anterior.
Retorna True se existe uma página subsequente ou anterior.
Retorna o número da página subseqüente. Note que este é um método "burro" e vai apenas retornar o número da página subseqüente, a página existindo ou não.
Retorna o número da página anterior. Note que este é um método "burro" e vai apenas retornar o número da página anterior, a página existindo ou não.
Retorna o índice iniciado em 1 do primeiro objeto na página, relativo a todos os objetos na lista do paginador. Por exemplo, quando se pagina uma lista com 5 objetos a 2 objetos por página, o start_index() da segunda página devolveria 3.
Retorna o índice iniciado em 1 do último objeto na página, relativo a todos os objetos na lista do paginador. Por exemplo, quando se pagina uma lista com 5 objetos a 2 objetos por página, o end_index() da segunda página devolveria 4.
Dec 26, 2011