Object Craft
E-mail: [email protected]
Release 0.06
July 1, 2002
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
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.
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:
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.
from albatross import SimpleApp, SimpleAppContext from albatross.cgiapp import Request
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')
class AppContext(SimpleAppContext): def __init__(self, app): SimpleAppContext.__init__(self, app)
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)
if __name__ == '__main__': app = App() app.run(Request())
This technique enables you to pass a value from the controller (the Python script) to the presentation (the HTML file/template).
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')
<p>Value #1: <al-input name="variable_1"></p> <p>Value #2: <al-value expr="variable_2"></p>
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).
<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.
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
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:
from albatross import SimpleSessionApp, SessionAppContext
class AppContext(SessionAppContext): def __init__(self, app): SessionAppContext.__init__(self, app)
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)
./al-session-daemon -h
And, here is an example of how to start it up:
./al-session-daemon -k mysessions.pid start
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.
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')
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:
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
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.
class AppContext(SessionAppContext): def __init__(self, app): SessionAppContext.__init__(self, app)
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)
if __name__ == '__main__': app = App() app.run(Request())
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')
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')
There are two parts to this question:
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.
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.