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.