Декоратор для удобного постраничного разбиения
Стандартное решение предлагаемое джанго для постраничного разбиения списка объектов - это класс django.core.paginator.ObjectPaginator
Здесь можно посмотреть примеры использования ObjectPaginator [djangoproject.com]
Однако, использование ObjectPaginator в голом виде не совсем удобно. В самом деле, нужно:
- извлечь номер страницы из GET-данных или URL запроса
- создать QuerySet объектов для пагинации
- создать ObjectPaginator, передав ему этот QuerySet
- получить объекты текущей страницы, путём вызова метода get_page у пагинатора
Вся эта рутина так и просится в декоратор. Без лишних слов, собственно, код декоратора )
Поясню, как я его использую. Дело в том, что все мои view возвращают не объект класса HttpResponse, но обыкновенный словарь, который потом обрабатывается декоратором render_to. Подробнее об этом вы можете прочитать в этой статье [web-brains.com]
Ну а в декораторе paged я просто дополняю этот словарь, который вернула моя view. Я кладу в словарь элементы с ключами page, pages и список объектов. Имя элемента со списком задаётся в первом позиционном аргументе декоратора. Чтобы декоратор работал, нужно из view вернуть QuerySet объектов для пагинации в элементе с ключом paged_qs.
Код ещё сырой, я его написал час назад. До этого я использова не такой навороченный декоратор. Если у вас есть замечания и предложения, с радостью выслушаю.
Ну, и, конечно, было бы неплохо, чтобы список со страничками сам строился ;-)
В этом нам поможет следующий inclusion tag.
А это pagination.html
Здесь можно посмотреть примеры использования ObjectPaginator [djangoproject.com]
Однако, использование ObjectPaginator в голом виде не совсем удобно. В самом деле, нужно:
- извлечь номер страницы из GET-данных или URL запроса
- создать QuerySet объектов для пагинации
- создать ObjectPaginator, передав ему этот QuerySet
- получить объекты текущей страницы, путём вызова метода get_page у пагинатора
Вся эта рутина так и просится в декоратор. Без лишних слов, собственно, код декоратора )
def paged(paged_list_name, per_page=10):
def decorator(func):
def wrapper(request, *args, **kwargs):
result = func(request, *args, **kwargs)
if not isinstance(result, dict):
return result
try:
page = int(request.GET.get('page', 1))
except ValueError:
page = 1
from django.core.paginator import ObjectPaginator
paginator = ObjectPaginator(result['paged_qs'], per_page)
result[paged_list_name] = paginator.get_page(page - 1)
result['page'] = page
result['pages'] = paginator.pages
return result
return wrapper
return decorator
Поясню, как я его использую. Дело в том, что все мои view возвращают не объект класса HttpResponse, но обыкновенный словарь, который потом обрабатывается декоратором render_to. Подробнее об этом вы можете прочитать в этой статье [web-brains.com]
Ну а в декораторе paged я просто дополняю этот словарь, который вернула моя view. Я кладу в словарь элементы с ключами page, pages и список объектов. Имя элемента со списком задаётся в первом позиционном аргументе декоратора. Чтобы декоратор работал, нужно из view вернуть QuerySet объектов для пагинации в элементе с ключом paged_qs.
Код ещё сырой, я его написал час назад. До этого я использова не такой навороченный декоратор. Если у вас есть замечания и предложения, с радостью выслушаю.
Ну, и, конечно, было бы неплохо, чтобы список со страничками сам строился ;-)
В этом нам поможет следующий inclusion tag.
@register.inclusion_tag('site/pagination.html',takes_context=True)
def pagination(context,adjacent_pages=5):
page_list = range(
max(1,context['page'] - adjacent_pages),
min(context['pages'],context['page'] + adjacent_pages) + 1)
lower_page = None
higher_page = None
if not 1 == context['page']:
lower_page = context['page'] - 1
if not 1 in page_list:
page_list.insert(0,1)
if not 2 in page_list:
page_list.insert(1,'.')
if not context['pages'] == context['page']:
higher_page = context['page'] + 1
if not context['pages'] in page_list:
if not context['pages'] - 1 in page_list:
page_list.append('.')
page_list.append(context['pages'])
get_params = '&'.join(['%s=%s' % (x[0],','.join(x[1])) for x in
context['request'].GET.iteritems() if not x[0] == 'page'])
if get_params:
get_params = get_params + '&'
return {
'get_params': get_params,
'lower_page': lower_page,
'higher_page': higher_page,
'page': context['page'],
'pages': context['pages'],
'page_list': page_list}
А это pagination.html
<div class="pagination">
{% ifnotequal pages 1 %}
Страницы:
{% if lower_page %}
<a href="?page={{ lower_page }}">«</a>
{% endif %}
{% for number in page_list %}
{% ifequal number "." %}...
{% else %}
{% ifequal number page %}{{ number }}{% endifequal %}
{% ifnotequal number page %}
<a href="?page={{ number }}">{{ number }}</a>
{% endifnotequal %}
{% endifequal %}
{% endfor %}
{% if higher_page %}
<a href="?page={{ higher_page }}">»</a>
{% endif %}
{% endifnotequal %}
</div>




















Comments