root/galaxy-central/eggs/WebHelpers-0.2-py2.6.egg/webhelpers/pagination/__init__.py @ 3

リビジョン 3, 8.3 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1"""Pagination for Collections and ORMs
2
3The Pagination module aids in the process of paging large collections of
4objects. It can be used macro-style for automatic fetching of large collections
5using one of the ORM wrappers, or handle a large collection responding to
6standard Python list slicing operations. These methods can also be used
7individually and customized to do as much or little as desired.
8
9The Paginator itself maintains pagination logic associated with each page, where
10it begins, what the first/last item on the page is, etc.
11
12Helper functions hook-up the Paginator in more conveinent methods for the more
13macro-style approach to return the Paginator and the slice of the collection
14desired.
15
16"""
17from routes import request_config
18from orm import get_wrapper
19
20def paginate(collection, page=None, per_page=10, item_count=None, *args, **options):
21    """Paginate a collection of data
22   
23    If the collection is a list, it will return the slice of the list along
24    with the Paginator object. If the collection is given using an ORM, the
25    collection argument must be a partial representing the function to be
26    used that will generate the proper query and extend properly for the
27    limit/offset.
28   
29    Example::
30   
31        # In this case, Person is a SQLObject class, or it could be a list/tuple
32        person_paginator, person_set = paginate(Person, page=1)
33       
34        set_count = int(person_paginator.current)
35        total_pages = len(person_paginator)
36   
37    Current ORM support is limited to SQLObject and SQLAlchemy. You can use any ORM
38    you'd like with the Paginator as it will give you the offset/limit data necessary
39    to make your own query.
40   
41    **WARNING:** Unless you pass in an item_count, a count will be performed on the
42    collection every time paginate is called. If using an ORM, it's suggested that
43    you count the items yourself and/or cache them.
44   
45    """
46    collection = get_wrapper(collection, *args, **options)
47    if not item_count:
48        item_count = len(collection)
49    paginator = Paginator(item_count, per_page, page)
50    subset = collection[paginator.current.first_item:paginator.current.last_item]
51   
52    return paginator, subset
53   
54   
55class Paginator(object):
56    """Tracks paginated sets of data, and supplies common pagination operations
57   
58    The Paginator tracks data associated with pagination of groups of data, as well
59    as supplying objects and methods that make dealing with paginated results easier.
60   
61    A Paginator supports list operations, including item fetching, length, iteration,
62    and the 'in' operation. Each item in the Paginator is a Page object representing
63    data about that specific page in the set of paginated data. As with the standard
64    Python list, the Paginator list index starts at 0.
65   
66    """
67    def __init__(self, item_count, items_per_page=10, current_page=0):
68        """Initialize a Paginator with the item count specified."""
69        self.item_count = item_count
70        self.items_per_page = items_per_page
71        self.pages = {}
72        self.current_page = current_page
73   
74    def current():
75        doc = """\
76Page object currently being displayed
77
78When assigning to the current page, it will set the page number for this page
79and create it if needed. If the page is a Page object and does not belong to
80this paginator, an AttributeError will be raised.
81
82"""
83        def fget(self):
84            return self[int(self.current_page)]
85        def fset(self, page):
86            if isinstance(page, Page) and page.paginator != self:
87                raise AttributeError("Page/Paginator mismatch")
88            page = int(page)
89            self.current_page = page in self and page or 0
90        return locals()
91    current = property(**current())
92   
93    def __len__(self):
94        return (self.item_count == 0) and 0 or (((self.item_count - 1)//self.items_per_page) + 1)
95   
96    def __iter__(self):
97        for i in range(0, len(self)):
98            yield self[i]
99   
100    def __getitem__(self, index):
101        # Handle negative indexing like a normal list
102        if index < 0:
103            index = len(self) + index
104       
105        if index < 0:
106            index = 0
107       
108        if index not in self and index != 0:
109            raise IndexError, "list index out of range"
110       
111        return self.pages.setdefault(index, Page(self, index))
112   
113    def __contains__(self, value):
114        if value >= 0 and value <= (len(self) - 1):
115            return True
116        return False
117
118class Page(object):
119    """Represents a single page from a paginated set."""
120    def __init__(self, paginator, number):
121        """Creates a new Page for the given ``paginator`` with the index ``number``."""
122        self.paginator = paginator
123        self.number = int(number)
124   
125    def __int__(self):
126        return self.number
127   
128    def __eq__(self, page):
129        return self.paginator == page.paginator and self.number == page.number
130   
131    def __cmp__(self, page):
132        return cmp(self.number, page.number)
133   
134    def offset():
135        doc = """Offset of the page, useful for database queries."""
136        def fget(self):
137            return self.paginator.items_per_page * self.number
138        return locals()
139    offset = property(**offset())
140   
141    def first_item():
142        doc = """The number of the first item in the page."""
143        def fget(self):
144            return self.offset
145        return locals()
146    first_item = property(**first_item())
147   
148    def last_item():
149        doc = """The number of the last item in the page."""
150        def fget(self):
151            return min(self.paginator.items_per_page * (self.number + 1),
152                self.paginator.item_count)
153        return locals()
154    last_item = property(**last_item())
155   
156    def first():
157        doc = """Boolean indiciating if this page is the first."""
158        def fget(self):
159            return self == self.paginator[0]
160        return locals()
161    first = property(**first())
162   
163    def last():
164        doc = """Boolean indicating if this page is the last."""
165        def fget(self):
166            return self == self.paginator[-1]
167        return locals()
168    last = property(**last())
169   
170    def previous():
171        doc = """Previous page if it exists, None otherwise."""
172        def fget(self):
173            if self.first:
174                return None
175            return self.paginator[self.number - 1]
176        return locals()
177    previous = property(**previous())
178   
179    def next():
180        doc = """Next page if it exists, None otherwise."""
181        def fget(self):
182            if self.last:
183                return None
184            return self.paginator[self.number + 1]
185        return locals()
186    next = property(**next())
187
188    def window(self, padding = 2):
189        return Window(self, padding)
190   
191    def __repr__(self):
192        return str(self.number)
193
194class Window(object):
195    """Represents ranges around a given page."""
196    def __init__(self, page, padding = 2):
197        """Creates a new Window object for the given ``page`` with the specified ``padding``."""
198        self.paginator = page.paginator
199        self.page = page
200        self.padding = padding
201   
202    def padding():
203        doc = """Sets the window's padding (the number of pages on either side of the window page)."""
204        def fset(self, padding):
205            self._padding = padding
206            if padding < 0: self._padding = 0
207            first_page_in_window = self.page.number - self._padding
208            self.first = first_page_in_window in self.paginator and (
209                self.paginator[first_page_in_window]) or self.paginator[0]
210            last_page_in_window = self.page.number + self._padding
211            self.last = last_page_in_window in self.paginator and (
212                self.paginator[last_page_in_window]) or self.paginator[-1]
213        def fget(self):
214            return self._padding
215        return locals()
216    padding = property(**padding())
217   
218    def pages():
219        doc = """Returns a list of Page objects in the current window."""
220        def fget(self):
221            return [self.paginator[page_number] for page_number in
222                range(self.first.number, self.last.number+1)]
223        return locals()
224    pages = property(**pages())
225
226    def __add__(self, window):
227        if window.paginator != self.paginator:
228            raise AttributeError("Window/paginator mismatch")
229        assert self.last >= window.first
230        return Window(self.page.next, padding=self.padding+1)
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。