]> git.parisson.com Git - teleforma.git/commitdiff
add name base paginator
authoryomguy <yomguy@parisson.com>
Tue, 17 Apr 2012 10:41:06 +0000 (12:41 +0200)
committeryomguy <yomguy@parisson.com>
Tue, 17 Apr 2012 10:41:06 +0000 (12:41 +0200)
teleforma/models.py

index 2322afc1986338bfbf71e8dbbfa5fd7317e438d5..00ef751de0847beb2cb7fa6128c0ac37ab379d8d 100755 (executable)
@@ -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