from __future__ import with_statement
As I write this, this blog system contains 3 published posts and 8 drafts. If you were to try to infer my level of engagement with technology from the activity on this blog, you might think I’ve given up and started selling used cars. For better or worse, that’s not the case.
Here are some things that I coulda/shoulda blogged about since I last posted in January:
- Tagging Dreams with Django
- Plotting the Future of Crosscheck
- New Gig: Second Rotation
- From Django to Rails (and Back)
- Encapsulating a Django Project
- Auditable Django Models
- Simplify WordPress Upgrades With Subversion
- The AppEngine Experience
- Building Web Apps on the T
- A Brief History of Freestyle
- Building Your Own Blog: Awesome or Chumpy?
- Boston BarCamp 2008
I’m a bad, bad blogger. This list doesn’t include any of the drafts that I actually began to write. But, as I look at this list, there’s a lot of interesting stuff here. I suspect that if I actually make myself write about the things that I’m thinking and working on, it will help motivate me to finish some of my projects. If I’m lucky, a few people might even read it, which will motivate me even more. Is this how life works for extroverts?
I recently started using the SearchManager from the Mercury Tide white paper on using MySQL full-text search with Django. It's been helpful, but I ran into a bug recently while trying to add a default filter to a SearchManager subclass.
The Boring Context
Rather than deleting objects from the database, my application sets a boolean flag to indicate that the content is not longer relevant. I wanted my manager to apply a filter to every query set to include only items that are not disabled. Here's what the manager class looks like:
class SearchableItemManager(SearchMangager): def __init__(self): zuper = super(SearchableItemManager, self) zuper.__init__(('name','description',)) def get_query_set(self): query = super(SearchableItemManager, self).get_query_set() return query.filter(is_enabled=True)
The Ugly Crash
When I made the change, I found that calling the
search() method raised a TypeError: "'NoneType' object is not iterable." The error occurred when the SearchQuerySet tried to construct the SQL for the MATCH…AGAINST clause. Somehow, the
_search_fields tuple on the SearchQuerySet was None.
The Mystery Solved
This had me baffled until I had a look at the _QuerySet code in Django. It seems obvious now, but adding an additional filter to a query set returns a clone of the original with the new filter added. The _QuerySet object contains a
_clone method that copies a hard-coded list of fields from the old QS to the new one. Naturally, that hard-coded list doesn't know anything about my
_search_fields, so the property has no value on the clone.
Now, depending on how much of a zealot you are about modifying “private” functions, there are two ways to fix this. The easiest method is to simply override the
_clone method and add the
_search_fields tuple to the clone. The alternative is to override every method that depends on the _clone method, and copy over the
_search_fields tuple for each one. I think that would be stupid, and will speak of it no further. Here's the code I added to generate happiness:
class SearchQuerySet(models.query.QuerySet): # ... code from the original Mercury Tide class def _clone(self, klass=None, **kwargs): zuper = super(SearchQuerySet, self) clone = zuper._clone(klass, **kwargs) clone._search_fields = self._search_fields return clone
One of the things that I’m most looking forward to about my ongoing transition to Boston is getting involved in the development community. I have no doubt that New Bedford has a few developers around, but the meet-up community is completely dead, and the chances of me making 3 hour round-trip to Boston on a week night just to talk shop are slim. But, now that I’m up there every day for work, you can expect to see me out on the town, hobnobbing with the geekiest of the geeks.
I went to my first meet-up last week: The eXtreme Tuesday Club. It sounds like it might involve jumping from a plane with a snowboard strapped to my feet while drinking Mountain Dew, but it’s actually a group for Extreme Programming (XP) zealots. I’m not actually a zealot about it, but I’ve seen it work brilliantly in the past and it’s an experience that I’d like to repeat. That single, trancendental experience doing full XP with a great team was probably the most stress-free, fun, and productive project that I’ve ever been involved with.
I had a great time at the meet-up. It wasn’t heavily attended, but it was great talking to the few people that were there about continuous integration, checked exceptions, and other geekery. There were a couple of guys from a local Agile shop, a woman from “a very large company”, and a sales guy from an IT services company. The sales guy was a bit out of his element, but he did manage to sit through my explanation of XP. I love trying to explain technical concepts to non-technical people, so I think I may have gotten more out of the experience than he did.
There’s a trick to blogging.
I don’t know what that trick is, but I intend to figure it out. I’ve had quite a few blogs in the past with sparse to middling success at maintaining them with new content. Maybe I ought to just throw in the towel and admit that I’m either too much of a perfectionist or too disorganized to maintain a blog successfully, but I can’t shake the feeling that I really ought to be doing this, and doing it well.
So, this is my latest attempt at staking out some digital territory in the crowded, geek-o-sphere. It’s Subakva, which means, for those of us who don’t speak esperanto, “underwater” (Prepare yourself for my upcoming blog entry on how to find an squatter-free domain name by learning obscure, artificial languages.)
If you’re interested in web technology, interface design, and all that Geek 2.0 jazz, I predict that there will be something worthwhile for you to read here in the future. If you’re not interested in any of that, then there’s nothing for you here but heartache and disappointment. Go now, with your spirit still intact.