Edgewall Software

Changes between Version 7 and Version 8 of HelperFunctions


Ignore:
Timestamp:
Sep 4, 2006, 5:18:38 PM (13 years ago)
Author:
cmlenz
Comment:

Add simple paginator example

Legend:

Unmodified
Added
Removed
Modified
  • HelperFunctions

    v7 v8  
    105105}}}
    106106
     107== paginate() ==
     108
     109A basic pagination routine written by [http://www.cmlenz.net/ Christopher Lenz].
     110
     111{{{
     112#!python
     113from math import ceil
     114
     115def paginate(items, page=0, max_per_page=10):
     116    """Simple generic pagination.
     117   
     118    Given an iterable, this function returns:
     119     * the slice of objects on the requested page,
     120     * the total number of items, and
     121     * the total number of pages.
     122   
     123    The `items` parameter can be a list, tuple, or iterator:
     124   
     125    >>> items = range(12)
     126    >>> items
     127    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
     128    >>> paginate(items)
     129    ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 12, 2)
     130    >>> paginate(items, page=1)
     131    ([10, 11], 12, 2)
     132    >>> paginate(iter(items))
     133    ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 12, 2)
     134    >>> paginate(iter(items), page=1)
     135    ([10, 11], 12, 2)
     136   
     137    This function also works with generators:
     138   
     139    >>> def generate():
     140    ...     for idx in range(12):
     141    ...         yield idx
     142    >>> paginate(generate())
     143    ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 12, 2)
     144    >>> paginate(generate(), page=1)
     145    ([10, 11], 12, 2)
     146   
     147    The `max_per_page` parameter can be used to set the number of items that
     148    should be displayed per page:
     149   
     150    >>> items = range(12)
     151    >>> paginate(items, page=0, max_per_page=6)
     152    ([0, 1, 2, 3, 4, 5], 12, 2)
     153    >>> paginate(items, page=1, max_per_page=6)
     154    ([6, 7, 8, 9, 10, 11], 12, 2)
     155    """
     156    if not page:
     157        page = 0
     158    start = page * max_per_page
     159    stop = start + max_per_page
     160
     161    count = None
     162    if hasattr(items, '__len__'):
     163        count = len(items)
     164
     165    try: # Try slicing first for better performance
     166        retval = items[start:stop]
     167    except TypeError: # Slicing not supported, so iterate through the whole list
     168        retval = []
     169        for idx, item in enumerate(items):
     170            if start <= idx < stop:
     171                retval.append(item)
     172            # If we already obtained the total number of items via `len()`,
     173            # we can break out of the loop as soon as we've got the last item
     174            # for the requested page
     175            if count is not None and idx >= stop:
     176                break
     177        if count is None:
     178            count = idx + 1
     179
     180    return retval, count, int(ceil(float(count) / max_per_page))
     181}}}
     182
     183=== Example usage ===
     184
     185{{{
     186#!xml
     187<div py:with="items, num_items, num_pages = paginate(range(1, 24), cur_page - 1)">
     188  <h1>Page ${cur_page} of ${num_pages}</h1>
     189  <ul><li py:for="item in items">${item}</li></ul>
     190  <hr />
     191  <py:for="num in range(cur_page, num_pages + 1)">
     192    <a href="?page=$num">$num</a>
     193  </py:for>
     194</div>
     195}}}
     196
     197That should result in the following output:
     198
     199{{{
     200#!xml
     201<div>
     202  <h1>Page 1 of 3</h1>
     203  <ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>
     204  <hr />
     205  <a href="?page=1">1</a>
     206  <a href="?page=2">2</a>
     207  <a href="?page=3">3</a>
     208</div>
     209}}}
     210
    107211== countoccurrences() / countdistinct() ==
    108212