# -*- coding: utf-8 -*- from functools import wraps from django.conf import settings from django.core.paginator import Paginator, InvalidPage, EmptyPage from django import forms from utils import safe_int # допустимые значения `per_page` _ALLOW_PER_PAGE = (10,20,50,75,100,) # по умолчанию ALLOW_PER_PAGE = getattr(settings, 'ALLOW_PER_PAGE', _ALLOW_PER_PAGE) class PaginationForm(forms.Form): """Форма для пагинатора со списком допустимых значений `per_page`.""" per_page = forms.ChoiceField(label=u'записей на странице', choices=zip(ALLOW_PER_PAGE, ALLOW_PER_PAGE), required=False) def save_per_page_value(func): """Декоратор. Если задан request.POST['per_page'], то сохранить его в куку. Имя куки - per_page, срок хранения - 1 год. """ @wraps(func) def wrapper(request, *args, **kwargs): output = func(request, *args, **kwargs) key = 'per_page' if request.method == 'POST' and key in request.POST: per_page = safe_int(request.POST[key]) if per_page in ALLOW_PER_PAGE: if hasattr(output, 'set_cookie'): max_age = 365*24*60*60 # год output.set_cookie(key, per_page, max_age) return output return wrapper def get_per_page_value(request): """Возвращает значение `per_page` (нужно для создания пагинатора). Последовательно ищет `per_page` в словарях request.POST и request.COOKIES. Если его там нет, возвращает самое первое значение из списка допустимых. """ per_page = None # если задан, взять per_page из post if request.method == 'POST' and 'per_page' in request.POST: per_page = safe_int(request.POST.get('per_page')) # иначе попробовать взять его из cookies elif 'per_page' in request.COOKIES: per_page = safe_int(request.COOKIES.get('per_page')) # проверить чтоб значение per_page было в списке допустимых if per_page not in ALLOW_PER_PAGE: per_page = ALLOW_PER_PAGE[0] return per_page def pagination(request, object_list, page_num=None, form_class=PaginationForm): """Создает и возвращает объект django.core.paginator.Paginator и, если form_class!=None, форму со списком допустимых значений `per_page`. """ per_page = get_per_page_value(request) # кол-во записей на странице # пагинатор paginator = Paginator(object_list, per_page) page_num = max(1, safe_int(page_num, 1)) try: objects = paginator.page(page_num) except (EmptyPage, InvalidPage): objects = paginator.page(paginator.num_pages) # форма form = None if form_class: form = PaginationForm(initial={'per_page': per_page,}) return objects, form