You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
3.1 KiB
75 lines
3.1 KiB
# -*- 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 commons.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
|
|
|