4.4 Adding Pagination Support to Popview
Description: Adding Pagination Support to Popview
Keywords: albatross

#
4.4 Adding Pagination Support to Popview

If the previous section we constructed a simple application for viewing the contents of a mailbox via the `poplib` module. One problem with the application is that there is no limit to the number of messages that will be displayed. In this section we will build pagination support into the message list page.

We will modify the application to display 15 messages on each page and will add buttons to navigate to the next and previous pages. The `pagesize` attribute of the `<al-for>` tag provides automatic pagination support for displaying sequences. The only extra code that we need to add is a `__len__` method to the `Mbox` class which returns the number of messages in the mailbox. This `__len__` method is needed to allow the template file to test whether or not to display a next page control.

The complete sample program is contained in the `samples/popview2` directory. Use the `install.py` script to install the sample.

    cd samples/popview2
    python install.py

Add a `__len__` method to the `Mbox` class in `popviewlib.py`.

    class Mbox:

        def __init__(self, name, passwd):
            self.mbox = poplib.POP3(pophost)
            self.mbox.user(name)
            self.mbox.pass_(passwd)

        def __getitem__(self, i):
            try:
                return Msg(self.mbox, i + 1)
            except poplib.error_proto:
                raise IndexError

        def __len__(self):
            len, size = self.mbox.stat()
            return len

Now we modify the template file `list.html`.

    <html>
     <head>
      <title>Message List</title>
     </head>
     <body>
      <al-for iter="m" expr="mbox" pagesize="15" prepare/>
      <al-form method="post">
       <al-if expr="m.has_prevpage()">
        <al-input type="image" prevpage="m" srcicons/left.gif" border="0">
       </al-if>
       <al-input type="submit" name="refresh" value="Refresh">
       <al-if expr="m.has_nextpage()">
        <al-input type="image" nextpage="m" srcicons/right.gif" border="0">
       </al-if>
      </al-form>
      <hr noshade>
      <table>
       <tr align="left">
        <td></td>
        <td><b>View</b></td>
        <td><b>To</b></td>
        <td><b>From</b></td>
        <td><b>Subject</b></td>
       </tr>
       <al-for iter="m" continue>
       <tr align="left" valign="top">
        <td><al-value expr="m.value().msgnum"></td>
        <td>
         <al-form method="post">
          <al-input type="image" name="detail" srcicons/generic.gif" border="0">
          <al-input type="hidden" name="msgnum" expr="m.value().msgnum">
         </al-form>
        </td>
        <td><al-value expr="m.value().hdrs['To']"></td>
        <td><al-value expr="m.value().hdrs['From']"></td>
        <td><al-value expr="m.value().hdrs['Subject']"></td>
       </tr>
       </al-for>
      </table>
      <hr noshade>
     </body>
    </html>

The `<al-for>` tag just below the `<body>` tag contains two new attributes; `pagesize` and `prepare`.

The `pagesize` turns on pagination for the `<al-for>` `ListIterator` object and defines the size of each page. In order to remember the current top of page between pages, the tag places the iterator into the session. When saving the iterator, only the top of page and pagesize are retained.

The `prepare` attribute instructs the `<al-for>` tag to perform all tasks except actually display the content of the sequence. This allows us to place pagination controls before the actual display of the list.