[albatross-users] Albatross Form Question

Andrew McNamara andrewm at object-craft.com.au
Sat Apr 3 00:33:52 EST 2004


>Unfortunately, now that I have finally sat down to write my first
>albatross application, I'm feeling very lost.  In addition to being new to
>albatross, I'm also a python newbie, so I am not sure if I am even
>approaching my problem from the right direction.

We've all been there. Fortunately Python is very logical and quick to
pick up.

>Outside of albatross, I currently create customer objects in python and
>manipulate them.  For instance:
[...]
>Most of the what the object does is simply manipulate a MySQL backend, but
>it also runs some checks.

Good.

>Inside albatross, I want to create forms (some of them multipaged and
>stateful) that will read and manipulate my customer object.
>
>After browsing the albatross docs, I came up with an albatross tag like
>this on a form:
>
>First Name: <al-input type="TEXT" name="firstName" expr="c.firstName()">
>
>When I load the form, it shows me an input field with the customer
>object's firstName() value inside it.  Good so far.
>
>The part that I'm hung up on is saving form input.  I am able to do it
>with something like this:
>
>def page_process(self, ctx):
>...
>c = customer(username)
>c.firstName(ctx.get_value('firstName'))
>c.lastName(ctx.get_value('lastName'))
>...and so on...
>
>This works but it feels kludgy.  It also seems totally in opposition to
>the spirit of albatross.  The bigger my form is the more it bloats my
>python code, and if I want to add a field to my form (that will be saved,
>anyhow), I have to edit the python script and that feels weird.

Albatross wants you to use a Model-View-Controller architecture. There's
discussion in the doco on this, but it doesn't go into much depth.

The idea is that you have a bunch of logic that implements the business
side of your application - this is the Model (your customer class). You
have a user interface - this is the View. In between, there's the
Controller, which glues the two together (doing conversions and
stuff). That's fair enough, but deciding what logic belong where is
difficult, and it's often not obvious why you're going to these lengths.

One advantage to splitting things up this way is that you can change the
business logic without effecting the presentation, or vica versa. And
because the business logic is separate, you could write unit-tests for
it without the added complexity of interacting with the user interface.
You can also use the same Model (business logic) with alternate interfaces
(web, gui, command line, etc).

What I'm trying to say is that you might find Albatross easier to get along
with if you introduce another layer of abstraction between your business
logic and the presentation.  You might have something like:

    class CustomerController:
        def __init__(self, c):
            ... copy relevent bits of c to attrs of self, possibly 
                formatting the data in friendly ways for the user 
                (eg dates).

        def update_cust(self, c):
            ... do the reverse, copying attributes of self to c,
                converting types, parsing dates, etc.

    And in the page module or class:

        def page_enter(ctx):
            ctx.locals.custcontrol = CustomerController(c)
            ctx.add_session_vars('custcontrol')

        def page_display(ctx):
            ctx.run_template(...)

        def page_process(ctx):
            if ctx.req_equals('submit'):
                ctx.locals.custcontrol.update_cust(c)

        def page_leave(ctx):
            ctx.del_session_vars('custcontrol')

    And in the template:

        <al-form>
            <al-input type="text" name="custcontrol.surname">
            <al-input type="text" name="custcontrol.given_name">
            ... etc ...
            <al-input type="submit" name="submit" value="Submit">
        </al-form>

You also ask if you have to update everything when you add another
attribute - there isn't really a simple answer to this. Many people have
"object relational" abstractions that they use for database driven web
applications - they tend to get complex quickly, but the simplest example
is a class (or metaclass) that presents the columns of a database row
as attributes on an instance, tracks when those attributes change, and
generates appropriate SQL to save them back. 

-- 
Andrew McNamara, Senior Developer, Object Craft
http://www.object-craft.com.au/



More information about the Albatross-users mailing list