Sunday, September 21, 2008

Using PyAMF and SQLAlchemy together

This past week I recieved the go-ahead to re-code the backend of our LIMS application with Python (it's currently PHP). It's not a minute too late, as I don't think I can stand typing another '->' or '$' without throwing something at the wall. I could go on about why I'm really sick of PHP and why Python rocks, but I'm sure you can read all about that elsewhere.

We'll be using Python's SQLAlchemy ORM, which kicks some serious ass. SQLAlchemy makes it amazingly simple to model complex relationships like inheritance hierarchies and many-to-many relationships that I could only implement with gobs of gnarly custom code in PHP.

Since we're already re-writing the backend we decided that we may as well tweak the Flex client at the same time. We are going to be making the switch from JSON to AMF for server-client communication, which will be more performant and allow us to transfer richer objects back and forth.

Python is pretty awesome for web-development, but the project that aims to support AMF (PyAmf) is still new and immature (but it does encode and decode as advertised and is under active development). In fact, the current stable release of PyAmf will not properly encode objects that are being managed by SQLAlchemy. There is a SQLAlchemy 'adapter' in the development branch of the PyAmf project that can be used, but I found the code to be lacking.

I decided to take matters into my own hands, and I am currently working on my own SQLAlchemy adapter that will hopefully work a little better. The code for my SQLAlchemy adapter can be found on Google code. It is not production ready, but if you want to experiment with it (tested only with SA 0.5), you should be able to drop it in the 'adapters' directory of the PyAmf 4.* branch to use it.

The adapter has 2 main features. It overrides the pyamf.util.get_attrs function so that the pyamf encoder skips any attributes of an object that are used by SQLAlchemy (_sa_instance_state, _sa_manager, etc), and it also identifies and translates SQLAlchemy collection objects, such as InstrumentedList objects.