Introduction
This is a simple example of an application that displays a list of people in an addressbook. The list can be sorted (by clicking on a table header) and filtered.
Note that the sort attribute is stored in a session variable whereas the filter string is not. That was purely to add a bit of interest to the application.
Running the Application
Put all of the files in an empty directory and create a subdirectory called "sessions" to store session data. Use "al-httpd app.app 8000" to start the application on port 8000.
Source Code
app.py
This is the application's main module. It containts the Albatross application. The App class should be fairly self explanatory (if you read the excellent documentation) but I will describe the ListPage class a little.
ListPage.page_enter() is called the first time the page is requested. The method ensures that the default sort attribute is set, if it did not exist already.
ListPage.page_process() processes requests sent to the page. If the request was a 'sort' (one of the table headers was clicked) then the new sort attribute is copied to the session variable' if the request was a 'clear_filter' then the filter string is reset to None.
ListPage.page_display() is called to display the page. It first retrieves a list of people. The list is sorted by the attribute name in the session variable and filtered by the filter string (if any). It then renders the page by running the template.
1 from albatross import *
2 import addressbook
3
4 class App(SimpleSessionFileApp):
5 '''AddressBook Albatross application'''
6
7 def __init__(self, base_url = '/', base_dir = '.'):
8 # Initialise base class
9 SimpleSessionFileApp.__init__(
10 self,
11 base_url = base_url,
12 template_path = base_dir,
13 start_page = ListPage.name,
14 secret = '-=secret=-',
15 session_appid = 'AdressBook',
16 session_dir = base_dir + '/sessions')
17
18 # Register page(s)
19 for page_class in (ListPage,):
20 self.register_page(page_class.name, page_class())
21
22
23 class ListPage:
24
25 name = 'list'
26
27 def page_enter(self, ctx):
28 # Sort by last_name by default
29 ctx.default_session_var('_sort', 'last_name')
30
31 def page_process(self, ctx):
32
33 if ctx.req_equals('sort'):
34 # Store the sort attribute in the session var
35 ctx.locals._sort = ctx.locals.sort
36
37 elif ctx.req_equals('clear_filter'):
38 # Set the filter string to None
39 ctx.locals.filter_string = None
40
41 def page_display(self, ctx):
42 # Get the list of people, sorting and filtering as necessary
43 ctx.locals.people = addressbook.get_all(
44 sort=ctx.locals._sort,
45 filter=getattr(ctx.locals, 'filter_string', None))
46 ctx.run_template('list.html')
47
48
49 # Create an application instance
50 app = App()
list.html
<html> <head> <title>Address Book</title> </head> <body> <p>Sorted by <al-value expr="_sort" /></p> <p> <al-form method="post"> <al-input type="text" name="filter_string" /> <al-input type="submit" name="filter" value="Filter" /> <al-input type="submit" name="clear_filter" value="Clear" /> </al-form> </p> <table> <tr> <th><al-a href="sort=first_name">First Name</al-a></th> <th><al-a href="sort=last_name">Last Name</al-a></th> <th><al-a href="sort=email">Email</al-a></th> </tr> <al-for iter="iter" expr="people"> <al-exec expr="person = iter.value()" /> <tr> <td><al-value expr="person.first_name" /></td> <td><al-value expr="person.last_name" /></td> <td><al-value expr="person.email" /></td> </tr> </al-for> </table> </body> </html>
addressbook.py
This module is a pretend database. It defines a class, Person, a pretend table of data, _people and a function to retrieve the list of people, get_all.
1 class Person:
2 '''A person'''
3 def __init__(self, id, first_name, last_name, email):
4 self.id = id
5 self.first_name = first_name
6 self.last_name = last_name
7 self.email = email
8
9
10 # List of people in the "database"
11 _people = [
12 Person(1, 'Michael', 'Neel', 'a@b.c'),
13 Person(2, 'Andrew', 'McNamara', 'd@e.f'),
14 Person(3, 'Dave', 'Cole', 'g@h.i'),
15 Person(4, 'Matt', 'Goodall', 'j@k.l'),
16 Person(5, 'Sheila', 'King', 'm@n.o'),
17 Person(6, 'Gregory', 'Bond', 'p@q.r'),
18 ]
19
20
21 def get_all(sort=None, filter=None):
22 '''
23 Get all people in the addressbook that match the optional filter,
24 optionally sorting the list by attribute name.
25 '''
26
27 # Use the full list to start with
28 people = _people
29
30 # Filter the people list to remove any that do not match
31 if filter:
32 filter = filter.lower()
33 people = [person for person in people if matches_filter(person, filter)]
34 # Sort the remaining list by attribute name
35 if sort:
36 dsu = [(getattr(person, sort), person) for person in people]
37 dsu.sort()
38 dsu = [item[1] for item in dsu]
39 people = dsu
40
41 return people
42
43
44 def matches_filter(person, filter):
45 '''
46 Return 1 (True) if the filter text appears in any of the attributes
47 of person
48 '''
49 if person.first_name.lower().find(filter) != -1 or \
50 person.last_name.lower().find(filter) != -1 or \
51 person.email.lower().find(filter) != -1:
52 return 1
53 return 0