Albatross How-to For Beginners

Object Craft

E-mail:

Release 0.06
July 1, 2002

 
Front Matter

Copyright © 2001 Object Craft All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. The end-user documentation included with the redistribution, if any, must include the following acknowledgement: "This product includes software developed by Object Craft." Alternately, this acknowledgement may appear in the software itself, if and wherever such third-party acknowledgements normally appear.

THIS SOFTWARE IS PROVIDED BY OBJECT CRAFT ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OBJECT CRAFT OR THEIR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Abstract:

This document explains how to do a number of simple tasks with Albatross. It is hoped that it will get a beginning Albatross user past a number of early questions and problems so that s/he can move on to more complex tasks.

See Also:

Albatross Users Mailing List
for discussion regarding application development using Albatross
Albatross Web Site
for information on the Albatross package
Apache Web Site
for information on the Apache web server
Mod Python Web Site
for information on mod_python



Contents

 
1 How-to Structure an Object-based Application

This section describes the structure of an object-based application. It can be used as a "template" for creating an application.

An object-based application is one which the controller is implemented by a Python class for each page in the application.

  1. Create the presentation - Create an HTML file for each page. This is the Albatross template file.

  2. Create the controller - Create a Python script. This script will contain the following items:

  3. Import the needed Albatross classes. For an object-based application, the following are appropriate:

    from albatross import SimpleApp, SimpleAppContext
    from albatross.cgiapp import Request
    

  4. Define a class for each page in the application. Here is a sample:

    class Page2:
        name = 'page2'
        def page_process(self, ctx):
            if ctx.req_equals('button_1'):
                if ctx.get_value('next_page') == 'page3':
                    ctx.set_page('page3')
            o
            o
            o
        def page_enter(self, ctx):
            o
            o
            o
        def page_leave(self, ctx):
            o
            o
            o
        def page_display(self, ctx):
            o
            o
            o
            ctx.run_template('page2.html')
    

  5. Define a context class as a subclass of SessionAppContext. Here is a sample:

    class AppContext(SimpleAppContext):
            def __init__(self, app):
                SimpleAppContext.__init__(self, app)
    

  6. Define an application class as a subclass of SimpleSessionApp. The constructor should call the constructor of the superclass and register each page (class) in the application. Also provide a create_context method that creates and returns an instance of your context class. Here is an example:

    class App(SimpleApp):
        def __init__(self):
            SimpleApp.__init__(self,
                base_url = 'dispatch.py',
                template_path = '.',
                start_page = 'page1',
                secret = 'tomato')
            for page_class in (Page1, Page2, Page3):
                self.register_page(page_class.name, page_class())
        def create_context(self):
            return AppContext(self)
    

  7. Create the "main" script. Here is a sample:

    if __name__ == '__main__':
        app = App()
        app.run(Request())
    

2 How-to Pass a Value to the Presentation

This technique enables you to pass a value from the controller (the Python script) to the presentation (the HTML file/template).

  1. In the controller (i.e. in the Python script), add the value to the the locals in the context. Here is a sample of the page_display method in the class defined for the page:

    class Page1:
        name = 'page1'
        def page_display(self, ctx):
            ctx.locals.variable_1 = 'a sample value'
            ctx.locals.variable_2 = 'another value'
            ctx.run_template('page1.html')
    

  2. In the presentation (i.e. the HTML page), use an Albatross tag to "capture" the value from the context. Here is a sample tag:

    <p>Value #1: <al-input name="variable_1"></p>
    <p>Value #2: <al-value expr="variable_2"></p>
    

3 How-to Pass a Value to the Controller

This technique enables you to capture input from the presentation (i.e. from the end-user at the Web browser) and pass those values back to the controller (the Python script).

  1. Add "input" items to the presentation (the HTML template):

    <p>Enter your name: <al-input type="text" name="user_name"></p>
    <p>Enter your phone: <input type="text" name="user_phone"></p>
    

    Note that the first item (user_name) also allows you to pass a value from the controller to the presentation. The second item (user_phone) does not.

  2. Capture the entered values in the controller. Here is a sample page_display method:

    class Page2:
        name = 'page1'
        def page_process(self, ctx):
            user_name = ctx.locals.user_name
            user_phone = ctx.locals.user_phone
            # Do something with user_name and user_phone.
            o
            o
            o
    

4 How-to Create a Session-based Application

This section describes how-to create an application that manages sessions and saves state across pages (responses) within each session.

Let's suppose that you start with a simple object-based application as described ``How-to Structure an Object-based Application''.

In order to convert this simple application into a session-based one, you will need to do the following:

  1. Import and inherit from SimpleSessionApp and SessionAppContext (instead of from SimpleApp and SimpleAppContext) as follows:

    from albatross import SimpleSessionApp, SessionAppContext
    

  2. Define your context class as a subclass of SessionAppContext (instead of AppContext). For example:

    class AppContext(SessionAppContext):
        def __init__(self, app):
            SessionAppContext.__init__(self, app)
    

  3. Define your application class as a subclass of SimpleSessionApp (instead of SimpleApp). Note that in addition to switching to the use of SimpleSessionApp, you will also need to add the keyword argument session_appid. Here is an example:

    class App(SimpleSessionApp):
        def __init__(self):
            SimpleSessionApp.__init__(self,
                base_url = 'dispatch.py',
                template_path = '.',
                start_page = 'page1',
                secret = 'tomato',
                session_appid = 'sampleapp')
            for page_class in (Page1, Page2, Page3):
                self.register_page(page_class.name, page_class())
        def create_context(self):
            return AppContext(self)
    

  4. Start the session server - In order to run your session application, you will need to start a session server. Albatross provides a session server that runs as a daemon. al-session-daemon is in the subdirectory session-server of the Albatross distribution. Get help by typing:

    ./al-session-daemon -h
    

    And, here is an example of how to start it up:

    ./al-session-daemon -k mysessions.pid start
    

5 How-to Manage Sessions

In this section, we explain how to control sessions from within your application. In particular, we'll describe how to create a new session and how to remove a session (e.g. when one of your end-users finishes with your application, and how to save state (values) across pages within a session.

  1. How-to create a session - Albatross does this for you automatically. If the request from the browser contains information about an existing session, that session is used, otherwise Albatross creates a new session.

  2. How-to remove a session - Albatross will delete idle sessions for you automatically. However, if you want your end users to be able to logout or exit from your application, for example, so that they can start a new session, then you will need to explicitly remove the session. For example, suppose you have a page from which the application can go no further. You could remove the session on entering the page. The user will never leave the page, but reloading the page will take them back to the beginning. Here is an example:

    class FinalPage:
        def page_enter(self, ctx):
            ctx.remove_session()
    

    Or, if the final page of your application contains a "Logout" or "Exit" button, you can remove the session in the page_process method of the class for that page like this:

    class FinalPage:
        def page_process(self, ctx):
            # Check for the logout button.
            if ctx.req_equals('logout'):
                ctx.remove_session()
                # Send the user back to the login page.
                ctx.set_page('login')
    

  3. How-to save session state across pages within the application - In order to direct Albatross to do this, you will "register" the variables that you want saved. Do this by calling add_session_vars, passing the names of the variables to be saved. Here is an example:

    class Page1:
        def page_enter(self, ctx):
            ctx.add_session_vars('user_name', 'user_phone')
    

    This tells Albatross to preserve these variables across pages. In Addition, you must also create these variables in the context. In Python code, the following will work:

    ctx.locals.user_name = name
    ctx.locals.user_phone = phone
    

    And, in HTML, an input item in a form will create the values. After doing this, you will be able to access these variables within the locals of the context object. For example in Python:

    name = ctx.locals.user_name
    phone = ctx.locals.user_phone
    

    And, since the values are in the local context, you will be able to reference these variables from your HTML code. For example:

    <al-value expr="user_name">
    <al-input name="user_phone">
    

Additional notes on session management:

6 How-to Convert an Object App to a Modular App

First, let's make clear what we are trying to do here. We are going to convert an application whose controller is implemented with one class (object) definition for each page (i.e. an object-based application) into an application whose controller is implemented with one module (.py file) for each page (a modular application).

Why would we do this? If the number of pages in your application has grown large, you may feel that you have too many classes.

We are going to assume that you already have an object-based application

  1. Create a "main" Python file in your application directory. Let's call it main.py.

  2. In main.py, import ModularSessionApp and SessionAppContext:

    from albatross import ModularSessionApp, SessionAppContext
    

    If you want your session state stored in the local file system, rather than in the session server's memory, then use ModularSessionFileApp and SessionFileAppContext instead. For example:

    from albatross import ModularSessionFileApp, SessionFileAppContext
    

    And, if you want a non-session application, use the ModularApp class instead.

  3. In main.py define a context class as a subclass of SessionAppContext (or SessionFileAppContext). Here is an example:

    class AppContext(SessionAppContext):
        def __init__(self, app):
            SessionAppContext.__init__(self, app)
    

  4. In main.py define an application class as a subclass of ModularSessionApp (or ModularSessionFileApp). Here is an example:

    class App(ModularSessionApp):
        def __init__(self):
            ModularSessionApp.__init__(self,
                base_url = 'dispatch.py',
                module_path = '.',
                template_path = '.',
                start_page = 'page1',
                secret = 'apricot',
                session_appid = 'sampleapp')
        def create_context(self):
            return AppContext(self)
    

  5. In main.py, define the ``main'' code, which should create and run the application instance. This code could look like the following:

    if __name__ == '__main__':
        app = App()
        app.run(Request())
    

  6. Now create a Python module for each page in your application. We will go through this process for a single page. Suppose you have a page page1.html (the presentation or view) and a class Page1 (the controller). Then, create a module called page1.py.

  7. Copy the class that defines the controller for Page1 into page1.py. It might look something like the following:

    class Page1
        name = 'page1'
        def page_process(self, ctx):
            if ctx.req_equals('button_1'):
                ctx.set_page('page2')
            elif ctx.req_equals('button_2'):
                ctx.set_page('page3')
        def page_display(self, ctx):
            ctx.run_template('page1.html')
    

  8. Now, again in page1.py, (1) remove the class line and (2) out-dent the methods so that they are top-level functions in the module. Also, (3) remove the self argument from each function. It might now look something like this:

    name = 'page1'
    
    def page_process(ctx):
        if ctx.req_equals('button_1'):
            ctx.set_page('page2')
        elif ctx.req_equals('button_2'):
            ctx.set_page('page3')
    
    def page_display(ctx):
        ctx.run_template('page1.html')
    

  9. Test your new modular application. Your conversion process is complete.

 
7 Transitions - How-to Move From Page to Page

There are two parts to this question:

  1. How do I test the conditions that determine which page is next?

  2. How do I transition to the new page?

We'll look at an example that tests several conditions. Here is an example from an object-based application:

class Page1State:
    name = 'Page1'
    def page_process(self, ctx):
        if ctx.req_equals('Button_1') and \
                ctx.get_value('next_page') == 'Page2' and \
                ctx.get_value('user_name') != '' and \
                ctx.get_value('user_code') > '0' and \
                ctx.locals.user_type == 'important':
            ctx.set_page('Page2')
        elif ctx.req_equals('Button_2') and \
                ctx.get_value('next_page') > 'Page3':
            ctx.set_page('Page3')

The above example checks to determine whether Button_1 was pressed and, if so, checks the values of input items next_page, user_name, and user_code and session variable user_type before transitioning to Page2. Let's assume that user_type is a variable set in a previous page and that it was registered with add_session_vars. Notice that set_page in the context object is called to tell Albatross which page is next. This is the Albatross mechanism for transitioning from one page to the next. The argument to set_page is the name passed to register_page (for object-based applications) or the name of the Python module for the page (for modular applications).

Now, here is an example from a modular application:

def page_process(ctx):
    if ctx.req_equals('Button_0'):
        ctx.set_page('Page3')
    elif ctx.req_equals('Button_1') and \
            ctx.get_value('next_page') == 'Page3':
        ctx.set_page('Page3')
    elif ctx.req_equals('Button_2') and \
            ctx.get_value('next_page') == 'Page4':
        ctx.set_page('Page4')
    elif ctx.req_equals('Button_3'):
        ctx.set_page('Page3')

Notice that this second example (from the modular application) is similar to the first example (from the object-based application), except that there are top-level functions in a module instead of methods in a class.

About this document ...

Albatross How-to For Beginners, July 1, 2002, Release 0.06

This document was generated using the LaTeX2HTML translator.

LaTeX2HTML is Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds, and Copyright © 1997, 1998, Ross Moore, Mathematics Department, Macquarie University, Sydney.

The application of LaTeX2HTML to the Python documentation has been heavily tailored by Fred L. Drake, Jr. Original navigation icons were contributed by Christopher Petrilli.