Web programming with Python and web.py: my experience

2nd November, 2010 - Posted by david

Quick Introduction

I’ve written the front page and an ajax handler for a web application using Python and web.py. Here I give my thoughts on using a niche product (web.py) and some of the coding issues I had to figure out on my own, in case some one has similar problems.

Background

Some time ago, I thought of an idea for a web app (keeping the nature of this separate from the post!). I’d been coding in PHP for quite some time and thought it might be a good idea to look at new languages. A friend of mine who had been working on a PHP Compiler at the time suggested I look at Python as a good language to get into. This seemed to make sense: big developer community, loads of documentation and libraries, works on almost every platform for almost any type of program, be it a web app, command line utility or fully fledged GUI program.

Having made the decision to opt for Python, next up was to choose a web framework. There are loads to choose from. I initially looked at Django, which came with a great online book, but I didn’t like how it handled logic in the web templates. Pylons and Turbogears also seemed good choices but just had a lot going on and were a bit too big for what I wanted. Then somehow I came across web.py, which was nice and simple with minimal extra baggage, unlike Pylons and Turbogears.

Web.py is much smaller than the other 3 frameworks. I knew this when I set out and kind of liked the fact that it was “one of the little guys”. However, working with niche software has it’s downsides. These can be summarised, with specific reference to web.py, as follows:

  • Documentation: while it existed and there were tutorials, the information available was by no means extensive.
  • Developer Community: not many people were working on moving the project forward (I was certainly in no position to) and it appeared development had stopped (I later found out this wasn’t to be the case, see below).
  • Job prospects: developing a web application in Python was partly to add to my skillset as a web developer. However, the chances of a future employer requiring a niche skill such as web.py was alot less likely than one of the bigger ones like Django or Pylons.
  • Similar problems: when encountering an error and Googling the solution or looking it up on Stackoverflow, it was often hard to find people who had encountered similar issues.
  • Shared servers: niche products aren’t always well supported on shared servers and can be hard to set up on them, whereas more popular software is more likely to be supported.

What I’m kind of trying to highlight here is the need to think of the broader picture when choosing to learn a certain technology. Do many other organisations use it? Are you going to waste loads of time figuring out how to do various things? Is the project moving forward? If the answer to any of these is “no” or “not really”, maybe you should look at something else.

One final note in defense of web.py though: I started looking at it when it was in version 0.33. It’s since moved to 0.34 and the website has had a total revamp: much better structured and more detailed information. Perhaps I gave up too soon!

Code Snippets

Some of these may seem like pretty basic things, but they’re not documented too well and took me a while to figure out. The examples here use summarised versions of 3 files, as follows:

  • webapp.py: Main Python file for the web application
  • base.html: Base template file. Would contain header, footer, navigation links etc.
  • index.html: Main index file, i.e. for the homepage. Uses base.html.

1. Global variables in your base template

One thing I had, and I’m sure is common to alot of sites, is a list of global variables, available to all pages across the site. So, how to access these global variables in the base template:

In your main application file (webapp.py), at the top, list your global variables as a dictionary (myglobals) and then pass this to your base template (base.html). We’ll use the example of a list of countries, something like:

#webapp.py
import web
# etc.

urls = (
    '/', 'index'
)

myglobals = {
   'countries': ('IE', 'Ireland'), ('UK', 'United Kingdom'), ('US', 'United States')
}

render = web.template.render('templates/', base='base', globals=myglobals)
app = web.application(urls, globals())

#rest of app...

Then, in your base.html the global variables are there to access via their dictionary key. So, to display a <select> box of countries, you can simply do

#base.html
$def with (page)
<html>
# html header and body code here
    <select name="country">
    $for code, country in countries:
        <option value="$code">$country</option>
    </select>
# rest of document
</html>

The variables countries in the for-loop in base.html corresponds to the countries entry in the myglobals dictionary defined in webapp.py

2. Accessing data specific to the main page from within the main page

You’ll often want to pass various data items to each specific page (in our case here I’m talking about index.html). Say we have a heading that only appears on our index.html but not required in the base template. Additionally, we’ll display the full date and time of the page load. First, we’d set this up in webapp.py as follows:

#... webapp.py, continued from above
import datetime

class index:
    def GET(self):
        data = {}
        data['page_title'] = 'Welcome!'
        data['datetime'] = datetime.datetime.now().strftime('%d %b %Y')
        return render.index(data)

This is then available in your index.html as follows:

#index.html
$def with (data)
<h2>${data['page_title']}</h2>
Rendered on ${data['datetime']}

The data passed to render.index in webapp.py corresponds to the data in $def with (data) in index.html

3. Calling your main page from your base template

This one’s probably covered well enough elsewhere, but I may as well give the details to continue the example. In base.html, you’ll have seen the first line as $def with (page). This page is the main page, i.e. index.html and corresponds to render.index(data) in our webapp.py. To pull this into your base.html, you’d do something like:

#base.html
$def with (page)
<html>
# html header and body code here
    <div id="main_content">
    $:page
    </div>
# rest of document
</html>

It’s the $:page bit that invokes the file the base template has been called with.

4. Accessing page specific data in your base template

It’s probably fair to say that your base.html will contain the <title> tag. So, to pass the title of say the index page to the base template, in our webapp.py we’d do something like (imagine the file continuing from above):

#... webapp.py, continued from above
class index:
    def GET(self):
        data = {}
        data['page_title'] = 'Welcome!'
        data['datetime'] = datetime.datetime.now().strftime('%d %b %Y')
        data['title'] = 'mysite.com:  for all your mysite needs'
        return render.index(data)

This then needs to be set up in our rendered index.html so it can be accessed in the template:

#index.html
$def with (data)
$var title:$data['title']

<h2>${data['page_title']}</h2>
Rendered on ${data['datetime']}

This is the accessed in our base.html as:

#base.html
$def with (page)
<html>
    <head>
    <title>$page.title</title>
    # etc.

So clearly here in base.html, $page.title corresponds to data['title'] in webapp.py.

Summary

It took me a while to figure out each of these various simple but common aspects, possibly because I was also learning Python as I was also learning web.py, but also in part due to the lack of documentation. Hopefully this Code Snippets part of the blog post will help any would-be new web.py developers getting their initial code up and running quicker than they would have before.

Tags: python web.py | david | 2nd Nov, 2010 at 14:43pm | No Comments

No Comments

Leave a reply

You must be logged in to post a comment.