from django.conf import settings from django.http import Http404 from types import ListType from DjHDGutils.misc import atoi import math """ Typical template example =========================== Template example for paginator:: {% if paginator.is_paginate %}
{% if paginator.get_prev_page %} « {% endif %} {% if paginator.get_prev_page_group %} ... {% endif %} {% for page in paginator.get_bar %} {% ifequal page paginator.page %} {{ page }} {% else %} {{ page }} {% endifequal %} {% endfor %} {% if paginator.get_next_page_group %} ... {% endif %} {% if paginator.get_next_page %} » {% endif %}
{% endif %} """ class Paginator(object): """ Paginator tool For use ``Paginator`` need to pass into template context instance of ``Paginator`` object with full query_set and current page number. Optional argument ``row_per_page`` can be omitted, then object will look for ``ROW_PER_PAGE`` in project settings file. """ def __init__(self, queryset, page=None, row_per_page=None, request=None): self._queryset = queryset self.request = request self._pages = None self.segment = None self._page = None self.row_per_page = row_per_page self._hits = 0 if page is not None or request is not None and self.row_per_page != 'all': self._calc(page) def _calc(self, page=None): if self.request and 'page' in self.request.GET and page is None: page = self.request.GET['page'] self._page = atoi(page,1) self.row_per_page = self.row_per_page or settings.PAGINATOR_PER_PAGE if type(self._queryset) is ListType: self._hits = len(self._queryset) else: self._hits = int(self._queryset.count()) self._pages = int(math.ceil(float(self._hits)/float(self.row_per_page))) if not self._pages: self._pages = 1 if self._page < 1 or self._page > self._pages: raise Http404 self.segment = 5 def _get_page(self): if self._page is None: self._calc() return self._page def _set_page(self, value): self._calc(value) page = property(_get_page, _set_page) def get_start_url(self): url='?' if self.request and len(self.request.GET.items()) > 0: qset = self.request.GET.copy() if qset.has_key('page'): del qset['page'] if len(qset) > 0: url += qset.urlencode() url += '&' return url def get_page_count(self): return self._pages def get_rows_count(self): return self._hits def get_offset(self): start = (self.page - 1) * atoi(self.row_per_page) end = self.page * atoi(self.row_per_page) return (start, end) def get_items(self): """ Return query set for current page """ if self.row_per_page == 'all': return self._queryset start, end = self.get_offset() return self._queryset[start : end] def get_bar(self): """ Return list of page numbers for current segment """ bar = [] for page in range(self.page-self.segment,self.page+self.segment+1): if page <= 0 or page > self.get_page_count(): continue bar.append(page) return bar def get_prev_page(self): if self.page - 1 <= 0: return None return (self.page - 1) def get_next_page(self): if self.page + 1 > self.get_page_count(): return None return (self.page + 1) def get_prev_page_group(self): if self.page - self.segment*2 - 1 <= 0: return None return (self.page - self.segment*2 - 1) def get_prev_page_segment(self): if self.page - self.segment - 1 <= 0: return None return (self.page - self.segment - 1) def get_next_page_group(self): if self.page + self.segment*2 + 1 > self.get_page_count(): return None return (self.page + self.segment*2 + 1) def get_next_page_segment(self): if self.page + self.segment + 1 > self.get_page_count(): return None return (self.page + self.segment + 1) def get_last_page(self): return int(self.get_page_count()) def is_paginate(self): return (self.row_per_page != 'all' and self.get_page_count() > 1) def set_page_by_position(self, position): self.page = int((position-1)/self.row_per_page)+1 def set_inverted_page_by_position(self, position): """ set inverted paginator page Exampte: inverted paginator for 33 items: page4: 33..24 page3: 23..14 page2: 13..4 page1: 3..1 """ i = self.get_rows_count() + 1 for p in range(1, self.get_page_count()+1): # [1,2,3,4] i -= self.row_per_page if i <= position: page = p break self.page = page