Archive

Posts Tagged ‘bottle’

Bottle’s view decorator and default variables

August 3rd, 2010

Bottle’s @view decorator provides a simple way to designate a template to render an HTML page. Your view function just has to return a dictionary, and its contents can be accessed from the template using the '{{ name }}' syntax.

The @view decorator can also take keyword arguments. These are treated as default template variables – if the dictionary returned by your view function doesn’t have a key for one of the keyword arguments then the template will use the value passed into the decorator, like so:

from bottle import view

@view('default.html', author='David Buxton')
def home():
    return {'title': 'Home page'}

That would render any instance of '{{ author }}' as 'David Buxton'. And then you can have another view function that overrides the keywords by returning a different value in the dictionary:

from bottle import view

@view('default.html', author='David Buxton')
def music():
    return {'title': 'Thalassocracy', 'author': 'Frank Black'}

And at that point I wonder what is the advantage of using keyword arguments with @view: you have to decorate each function separately, and if you want to override a keyword in your return dictionary then it would be easier not to specify the keyword in the first place.

Thus the real point of using keywords with the @view function is only apparent if you curry the @view decorator with keywords first so that you can re-use the curried decorator and avoid repeating yourself.

Someday I will re-write the previous sentence. Until then, sorry.

Instead of passing a default author each time as in the examples above, let’s make a new @view decorator (using Python’s functools module) and then use that on each view function:

import functools
from bottle import view

view = functools.partial(view, author='David Buxton')

@view('default.html')
def home():
    return {'title': 'Home page'}

@view('default.html')
def music():
    return {'title': 'Thalassocracy', 'author': 'Frank Black'}

The new decorator means you get the default keyword arguments wherever you use @view while permitting any function to override those defaults in the dictionary it returns.

And if you wanted to get really lazy you could even pass in a template name when wrapping the decorator with functools.partial, however you would not be able to use your wrapped decorator to change the template name because it is a positional argument (like what it explains here in the functools documentation). You would also have to call the decorator with no arguments like '@defaultview()'. So forget I mentioned it.

I’m not saying you are lazy.

david ,

Django-style routing for Bottle

July 26th, 2010

Bottle provides the @route decorator to associate URL paths with view functions. This is very convenient, but if you are a Django-reject like me then you may prefer having all your URLs defined in one place, the advantage being it is easy to see at a glance all the different URLs your application will match.

Updated: I have re-written this post and the example to make it simpler following Marcel Hellkamp’s comments (Marcel is the primary author of Bottle). My original example was needlessly complicated.

It is possible to have a Django-style urlpatterns stanza with a Bottle app. Here’s how it can work:

from bottle import route

# Assuming your *_page view functions are defined above somewhere
urlpatterns = (
    # (path, func, name)
    ('/', home_page, 'home'),
    ('/about', about_page, 'about'),
    ('/contact', contact_page, 'contact'),
)

for path, func, name in urlpatterns:
    route(path, name=name)(func)

Here we run through a list where each item is a triple of URL path, view function and a name for the route. For each we simply call the route method and then invoke it with the function object. Not as flexible as using the decorator on a function (because the @route decorator can take additional keyword arguments) but at least you can have all the routes in one place at the end of the module.

Then again if you have so many routes that you need to keep them in a pretty list you probably aren’t writing the simple application that Bottle was intended for.

(This was tested with Bottle’s 0.8 and 0.9-dev branches.)

david , ,