After converting 70+% of a project at work from Django to TurboGears over a week and a bit, and starting at rewriting an existing TurboGears project of mine to Pylons, quite a few things have interested me about the exercises.

Standard disclaimer about this just being my personal feelings and not some scientific test applies.  I've used TurboGears (90% own projects) a lot longer than I've used Django and Pylons, and I've used Django (50% work projects) a little bit more than I've used Pylons (only own projects so far).  I also prefer tea to coffee, tcsh to bash, and winter to summer.

... 

At work, we're translating an existing Django application to TurboGears.  As expected, pretty much the largest chunk of work revolved around the ORM.  We're going to be using Elixir as a light layer on top of SQLAlchemy - of the various options around technologies for templating, framework, and so forth, it seems SQLAlchemy is the universal (amongst, you know, three people) choice for the ORM (while the Django/TurboGears and Genshi/Django/ClearSilver debates raged).

Anyway, that's incidental.

When using Django (0.95), we had to add a search_path to the Django database connector for PostgreSQL, because Django didn't support specifying the schema that the tables managed by the ORM used.  I got a bit side-tracked trying to do the same for SQLAlchemy, since searching for "sqlalchemy schema" wasn't getting me anywhere, since schema has multiple meanings.

In the end, it's trivially simple - just pass the schema in the table options.  Since Elixir is a thin layer on top of SQLAlchemy which tries not to limit the functionality of SQLAlchemy itself, it's quite simple - the using_table_options statement can pass the schema to the table options (if that wasn't obvious from the name of the statement):

class Channels(Entity):
    has_field('desc', Unicode(100))
    
    belongs_to('settings', of_kind='Settings')
    
    using_options(tablename='channels')
    using_table_options(schema='ips')

There was a small bug in Elixir's relationship management code that meant that cross-schema relationships didn't work despite SQLAlchemy supporting it.  I sent a one-line patch to the mailing list and it is fixed now.

With per-table schema support in SQLAlchemy, we can also create the database with the tables in the correct schema - something we couldn't do before.  Nor, likely, anything we'd ever do with this project.  But it's nice that we can in future projects.

The next Cape Town Python User Group Meeting will be meeting tomorrow 2pm to 4pm at The Bandwidth Barn in the centre of Cape Town.  The main talk will be on Plone by Roche Compaan, CEO of Stellenbosch-based Plone gurus Upfront Systems.  I'll be giving a short talk on SQLAlchemy and Elixir.  Also, Simon Cross says he'll head a discussion on func_closure.

Once you've modeled the core objects, and then done the core aggregation logic for feeds and posts, you have pretty much everything else to do.  At the very least, you're going to want to put this together in some sort of interface - either for users to view, or for programs to check against.  And, if you're trying to build something like Amatomu, you've got a lot more work to do.

There are a number of additional standards above the original RSS (which a non-trivial amount of feeds probably still use), and those additional standards allow you to capture more metadata about the posts.  Atom has a standard around categories, and there are a few other ways people indicate categories in their feeds as well (and they may just call them "tags").  Someone might "geotag" their posts using GeoRSS.  There are ways to indicate the license of your work - especially with Creative Commons licenses.  There are podcasts using enclosures, and vodcasts which may or may not be using Yahoo!'s Media RSS, and all sorts of other stuff in the feeds you're aggregating.

Over on Eric Edelstein's, on talk of building another blog aggregator (to compete with Afrigator and Amatomu - listed in alphabetical order so as not to denote preference), I boasted at how easy it is to build the aggregator portion of it.  (Well, I'm fairly certain I did.  It seems the comments have all disappeared.  I'm not the only one pretty sure there were comments there...)

I did it quite significantly differently before, but I'm now building another version of the aggregator, hopefully in a way that gets rid of most of the tedium of aggregation, but allowing the results to be stored in whatever way the developer-user wants, and to allow capturing more about the feeds and posts than a generic aggregator will.

While I wanted to abstract away the particular model, I started with models for Feed and Post as a beginning, using Elixir, drawing inspiration on fields and definitions from the FeedJack aggregator for Django.