From e640f69136ba806ec1eadaf704a06577cb9b5f12 Mon Sep 17 00:00:00 2001 From: yomguy Date: Tue, 17 Apr 2012 12:41:06 +0200 Subject: [PATCH] add name base paginator --- teleforma/models.py | 104 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/teleforma/models.py b/teleforma/models.py index 2322afc1..00ef751d 100755 --- a/teleforma/models.py +++ b/teleforma/models.py @@ -39,6 +39,7 @@ import re import pwd import time import urllib +import string import datetime import mimetypes import telemeta @@ -52,6 +53,7 @@ from teleforma.fields import * from django.contrib.contenttypes import generic from notes.models import Note import jqchat.models +from django.core.paginator import InvalidPage, EmptyPage app_label = 'teleforma' @@ -400,3 +402,105 @@ class Profile(models.Model): db_table = app_label + '_' + 'profiles' verbose_name = _('profile') + +class NamePaginator(object): + """Pagination for string-based objects""" + + def __init__(self, object_list, on=None, per_page=25): + self.object_list = object_list + self.count = len(object_list) + self.pages = [] + + # chunk up the objects so we don't need to iterate over the whole list for each letter + chunks = {} + + for obj in self.object_list: + if on: obj_str = str(getattr(obj, on)) + else: obj_str = str(obj) + + letter = str.upper(obj_str[0]) + + if letter not in chunks: chunks[letter] = [] + + chunks[letter].append(obj) + + # the process for assigning objects to each page + current_page = NamePage(self) + + for letter in string.ascii_uppercase: + if letter not in chunks: + current_page.add([], letter) + continue + + sub_list = chunks[letter] # the items in object_list starting with this letter + + new_page_count = len(sub_list) + current_page.count + # first, check to see if sub_list will fit or it needs to go onto a new page. + # if assigning this list will cause the page to overflow... + # and an underflow is closer to per_page than an overflow... + # and the page isn't empty (which means len(sub_list) > per_page)... + if new_page_count > per_page and \ + abs(per_page - current_page.count) < abs(per_page - new_page_count) and \ + current_page.count > 0: + # make a new page + self.pages.append(current_page) + current_page = NamePage(self) + + current_page.add(sub_list, letter) + + # if we finished the for loop with a page that isn't empty, add it + if current_page.count > 0: self.pages.append(current_page) + + def page(self, num): + """Returns a Page object for the given 1-based page number.""" + if len(self.pages) == 0: + return None + elif num > 0 and num <= len(self.pages): + return self.pages[num-1] + else: + raise InvalidPage + + @property + def num_pages(self): + """Returns the total number of pages""" + return len(self.pages) + +class NamePage(object): + def __init__(self, paginator): + self.paginator = paginator + self.object_list = [] + self.letters = [] + + @property + def count(self): + return len(self.object_list) + + @property + def start_letter(self): + if len(self.letters) > 0: + self.letters.sort(key=str.upper) + return self.letters[0] + else: return None + + @property + def end_letter(self): + if len(self.letters) > 0: + self.letters.sort(key=str.upper) + return self.letters[-1] + else: return None + + @property + def number(self): + return self.paginator.pages.index(self) + 1 + + def add(self, new_list, letter=None): + if len(new_list) > 0: self.object_list = self.object_list + new_list + if letter: self.letters.append(letter) + + def __repr__(self): + if self.start_letter == self.end_letter: + return self.start_letter + else: + return '%c-%c' % (self.start_letter, self.end_letter) + + \ No newline at end of file -- 2.39.5