You are here: Home Articles And now for something completely different
Navigation
OpenID Log in

 

And now for something completely different

by Martin Aspeli last modified Sep 06, 2007 09:38 AM

Experiences using Pylons

Recently, I've had the opportunity to play with Pylons, a Python web framework that I understand is not too dissimilar to Ruby-on-Rails in functionality and philosophy. Pylons is built on a lot of cutting-edge Python web technologies, such as as Paste for general web server functionality, a variety of templating languages including Genshi (which rocks), and SQLAlchemy (my favourite Python library) for database integration.

This particular project needed to be delivered rapidly, and a relational database (in our case MySQL) was deemed the most appropriate data store. There are no content management requirements - rather, we will have there or four main screens allowing manipulation of data in the database, plus some rudimentary user management.

Thankfully, we have not had to worry about making re-usable themes, internationalisation, localisation or accessibility much at all. All users will have recent browsers, and none will have JavaScript turned off. In short - it's a pretty simple web application, with fairly demanding time scales.

We have focused a lot on usability - not at least the speed with which users can interact with the system. System performance is not so much of an issue, but the interaction patterns need to be pretty slick. That has meant a lot of AJAX and JavaScript-based UI. I will blog about that separately, later on.

Using Pylons

It's pretty simple to get started with Pylons. Once you've installed the Pylons egg, you can do:

>>> paster create -t pylons myproject

At this point, you will get a new egg, complete with a setup.py file, for your application, with the usual boilerplate.

A file called development.ini sets project options, such as the main database connection, whether or not to enable debugging features and so on. It also sets the port for the web server, which is wired in using WSGI magic. WSGI, if you're not familiar with it, is a pretty powerful means of chaining together Python web applications. Pylons uses it to give you an interactive Python debug prompt in the browser (a bit like Clouseau for Plone) when you get a traceback. Incredibly useful.

To run the application, you just do:

>>> paster serve --reload development.ini

The --reload bit ensures that if you change any Python code, your application is automatically restarted. A restart takes a second or two, making development pretty efficient.

Having the whole application in one egg is pretty nice. It means that you can deploy it as a standalone package. You don't need to install it (even in develop mode) during development, but to deploy, you'd just extract an archive of the package and do:

>>> python setup.py install


You can have a number of dependencies in setup.py, of course. There are also facilities to run bootstrap code (from a websetup.py module), e.g. to initialise your database or perform other configuration. For serious deployment, I imagine you'd use a caching solution such as Varnish or Squid, Apache and/of FastCGI in front of Pylons.

Working with the code

The Pylons layout you get from the paster template is pretty straightforward. There is a public/ directory, which is like a static web root. Style sheets, JavaScript files and static HTML can go here. The 'model' module contains SQLAlchemy setup code and other database-related things. There is a generated 'lib' module that imports the most important parts of Pylons for you, where you can also add additional utility code.

You are not supposed to re-generate the code in that you might do with, say, ArchGenXML in Plone. There are no protected code sections. You get a running application out of the box, but you're meant to modify it to suit your needs. This does potentially mean that migrating to future versions of the framework requires you to understand how things have changed in more detail, but in practice it works pretty well. The generated code is well commented and for the most part sensible. Some of the more ideosyncratic WSGI setup stuff I've chosen to ignore, but I'm sure it wouldn't be hard to learn how to tweak it, should I need to.

Controllers

The main logic happens through controllers. A library called Routes is used to map URLs onto controllers, so you can have pretty customised URL schemes, but the defaults are quite sensible.

To create a new controller, Pylons uses a feature of Paste where you can have context-sensitive commands (where the "context" is an egg, basically). To create a new controller, you'd do:

>>> paster controller mycontroller

It then creates the necessary parts, in particular 'controllers/mycontroller.py'. This has a method 'index()' and may look like this:

from myapp.lib.base import *
from myapp impotr model

class MyController(BaseController):

    def index(self):
        c.some_variable = 'foo'
        return render("mytemplate")

To access this, the standard URL would be http://localhost:5000/mycontroller/index, or just http://localhost:5000/mycontroller. You can add new methods and they are accessible immediately under the URL (Routes maps the first part of the URL to a controller and the second part to a method on that controller).

You'll notice a few globals as well. These are imported from the generated lib.base module, and includes utility functions like render() (which renders a template from the templates/ folder using the current templating language), redirect() or abort() (which raises an HTTP exception). The 'c' variable is a global that is reset for each request, but is used to store arbitrary information that can then be fetched in a rendered template. A fairly common pattern is for a controller to perform some calculations (for example using the SQLAlchemy objects in the 'model' module), save the results in the 'c' variable and call a template, which then inspects the 'c' variable and renders the results. 'request' and 'response' are also global singletons, which hold request parameters and so on.

I initially felt a little uncomfortable with this use of globals, but it is very convenient, and controlled quite well because you can change how the 'lib.base' module manages them.

The good and the bad

Pylons has been pretty good to us. It's relatively easy to learn, and most things work as you'd expect. The documentation is lacking in some areas. For example, it's difficult to work out the best way of managing users and sessions (we've settled on using Authkit). There was also a bit of a wobble around how best to use SQLAlchemy - we're still on SQLAlchemy 0.3 and the SAContext integration module; that seems to be dead in favour of using SQLAlchemy 0.4 (currently in beta) instead. Some of the documentation has been inconsistent or changing around this, though things seem to be settling down both in Pylons-land and SQLAlchemy-land.

I'm not convinced I'd use Pylons to build a very large and complex application - at least not until I'd had more experience and there was more "end-to-end" documentation, but most projects are not very large or very complex. I'm pretty sure that I'll go back to Pylons the next time I need to build an RDBMS-driven simple (non-CMS) web application... unless I specifically want the Zope way of working, in which case I'd probably go for Grok.

Document Actions
Plone Book
Professional Plone 4 Development

I am the author of a book called Professional Plone Development. You can read more about it here.

About this site

This Plone site is kindly hosted by: 

Six Feet Up