ほんじゃらねっと

ダイエット中プログラマのブログ

新しくなったPaginatorをページリンク機能をつけて使う

djangoのページング機能の使い方が変わったようなので、
それに合わせてページリンクを表示する機能を作った。
また使いそうなので保管。


以前のバージョンで使用していた、BetterPaginatorを参考にした。
http://d.hatena.ne.jp/piro_suke/20070827/1188202390


project_dir/utils.py

import string
from django.core.paginator import Page, InvalidPage
class BetterPage(Page):
def __init__(self, page, link_template):
self.link_template = link_template
Page.__init__(self, page.object_list, page.number, page.paginator)
def previous_link(self):
if self.has_previous():
tpl = string.Template(self.link_template)
return tpl.safe_substitute({"page": self.number - 1})
else:
return None
def next_link(self):
if self.has_next():
tpl = string.Template(self.link_template)
return tpl.safe_substitute({"page": self.number + 1})
else:
return None
def make_page_links(self, start, end):
tpl = string.Template(self.link_template)
return [(p+1, tpl.safe_substitute({"page": p + 1}), (p+1 == self.number)) for p in range(start, end)]
def page_links(self):
return self.make_page_links(0, self.paginator.num_pages)
def windowed_page_links(self, window_size=5):
links = []
if self.paginator.num_pages <= window_size:
links = [self.page_links()]
elif self.number - window_size/2 <= 3:
links = [self.make_page_links(0, window_size), self.make_page_links(self.paginator.num_pages-2, self.paginator.num_pages)]
elif self.number + window_size/2 > self.paginator.num_pages - 2:
links = [self.make_page_links(0, 2), self.make_page_links(self.paginator.num_pages-window_size, self.paginator.num_pages)]
else:
links = [self.make_page_links(0, 2),
self.make_page_links(self.number-window_size/2-1, self.number+window_size/2-1),
self.make_page_links(self.paginator.num_pages-2, self.paginator.num_pages)]
return links

project_dir/urls.py

from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^list/$', 'project_dir.app_dir.views.show_list'),
(r'^list/p(?P<page_number>\d+)/$', 'project_dir.app_dir.views.show_list'),
(r'^list/user/(?P<user_name>[0-9a-zA-Z_\-])/$', 'project_dir.app_dir.views.show_user_list'),
(r'^list/user/(?P<user_name>[0-9a-zA-Z_\-])/p(?P<page_number>\d+)/$', 'project_dir.app_dir.views.show_user_list'),
)

project_dir/app_dir/views.py

from django.core.paginator import QuerySetPaginator, InvalidPage
from project_dir.utils import *
from project_dir.app_dir.models import *
def show_list(request, page_number=1):
article_list = Article.objects.all()
article_paginator = QuerySetPaginator(article_list, 10)
article_page = BetterPage(article_paginator.page(page_number), '/list/p${page}/')
return render_to_response('article_list.html', {'page': article_page,}, context_instance=RequestContext(request))
# 絞り込み条件付の場合
def show_user_list(request, user_name, page_number=1):
article_list = Article.objects.all(user_name=user_name)
article_paginator = QuerySetPaginator(article_list, 10)
article_page = BetterPage(article_paginator.page(page_number), '/list/user/%s/p${page}/' % (user_name,))
return render_to_response('article_list.html', {'page': article_page,}, context_instance=RequestContext(request))

article_list.html

...
{% include "pager.html" %}
{% for article in page.object_list %}
<h3>{{ article.title }}</h3>
{% endfor %}
{% include "pager.html" %}
...

pager.html

<div class="paginator">
{% if page.has_previous %}
<a class="arrow" href="{{ page.previous_link }}">&#171;</a>
{% else %}
<span class="disabled arrow">&#171;</span>
{% endif %}
{% for s in page.windowed_page_links %}
{% if not forloop.first %}<span class="omitted-page">...</span>{% endif %}
{% for p in s %}
{% if p.2 %}
<span class="current-page">{{ p.0 }}</span>
{% else %}
<a class="other-page" href ="{{ p.1 }}">{{ p.0 }}</a>
{% endif %}
{% endfor %}
{% endfor %}
{% if page.has_next %}
<a class="arrow" href="{{ page.next_link }}">&#187;</a>
{% else %}
<span class="disabled arrow">&#187;</span>
{% endif %}
<div style="clear: left;"></div>
</div>

paginator.css

.paginator {
margin: 0 0 10px 0;
}
.paginator .arrow {
display: block;
float: left;
padding: 5px;
margin: 0 5px 0 0;
text-decoration: none;
color: #00c;
}
.paginator .disabled {
color: #ccc;
background-color: #eee;
}
.paginator .other-page {
display: block;
float: left;
padding: 5px;
margin: 0 5px 0 0;
text-decoration: none;
border: 1px solid #ccc;
color: #00c;
}
.paginator .current-page {
display: block;
float: left;
padding: 5px;
margin: 0 5px 0 0;
text-decoration: none;
border: 1px solid #ccc;
color: #00c;
font-weight: bold;
background-color: #fff;
}
.paginator .omitted-page {
display: block;
float: left;
padding: 5px;
margin: 0 5px 0 0;
color: #000;
}


まだあまりテストできていないので、データの数が増えると
動かなかったりするかもしれない。