July 30, 2010

web2py and metaclasses

Filed under: Uncategorized — mdipierro @ 2:26 pm


In the web2py world we always think about how to we make things easier for users. Here we want to show how you can use metaclasses to make your code very readable.

Out goal is to define some new syntax that has immediate meaning in English and can be reused in any web2py application.


Create an empty application (called for example thing_manager) and define

# black box
is_a = type('_',(),{'__getattr__':(lambda s,n: (lambda *a, **b: db.define_table(n,*a,**b)))})()
with_a = type('_',(),{'__getattr__':(lambda s,n: (lambda *a, **b: Field(n,*a,**b)))})()
this = type('_',(),{'__getattr__': (lambda s,n: db[n][request.args(0)])})()
please = crud
get_me = lambda a,*b,**c: db(a).select(*b,**c)
delete = lambda a,*b,**c: db(a).delete(*b,**c)
update = lambda a,*b,**c: db(a).update(*b,**c)
to_visitor = lambda *a: dict(page=DIV(*[DIV(i) for i in a]))
# end black box

The model

Now in your model you can define tables using the new syntax:

the_thing = is_a.thing(with_a.name(), with_a.category())
my_things = the_thing.id>0

where ‘thing’ is the name of the table, ‘name’ and ‘category’ are fields. You can specify named field attributes of name and category using normal Field(…) attribute syntax such as in


The Controller

Now in the default controller you can use the new syntax to define functions. Here is one for example:

def index():
    if this.thing:
        form = please.update(the_thing, this.thing)
        form = please.create(the_thing)
    things = get_me(my_things)
    return to_visitor(form,things)

This function can be called by
(will make a create interface for thing) or
(will make an update for for thing with id==1)

This action creates a complete thing_management interface. get_me(my_things) returns all current thing records. please.create and please.update simply map into the corresponding crud functions.


Here is how to looks like:

Other class

Of course there is nothing special about thing. Let’s use the same trick for a table “product” and different actions:

the_product = is_a.product(with_a.name(), with_a.price('double'))
my_products = the_product.price>0.0

# http://...new_product                                                                                                        
def new_product():
     return to_visitor(please.create(the_product))

def update_product():
     return to_visitor(please.update(the_product,this.product))

def list_products():
     products = get_me(my_products)
     return to_visitor(products)

Some explanation

The magic happens in is_a, with_a and this. There are instances of three different temp classes defined by the type function. They take attributes of arbitrary names and return lambda function that return the desired function:

  • is_a.thing(…) maps into db.define_table(‘thing’,….)
  • with_a.name(…) maps into Field(‘name’,….)
  • this.thing() maps into db[‘thing’][request.args(0)] this standard web2py syntax for fetching the record with id==request.args(0) (the [id] in http://…/index/%5Bid%5D) or None if the record does not exist.

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: