E-Scribe : a programmer’s blog

About Me

PBX I'm Paul Bissex. I build web applications using open source software, especially Django. Started my career doing graphic design for newspapers and magazines in the '90s. Then wrote tech commentary and reviews for Wired, Salon, Chicago Tribune, and others you never heard of. Then I built operations software at a photography school. Then I helped big media serve 40 million pages a day. Then I worked on a translation services API doing millions of dollars of business. Now I'm building the core platform of a global startup accelerator. Feel free to email me.


I co-wrote "Python Web Development with Django". It was the first book to cover the long-awaited Django 1.0. Published by Addison-Wesley and still in print!


Built using Django, served with gunicorn and nginx. The database is SQLite. Hosted on a FreeBSD VPS at Johncompanies.com. Comment-spam protection by Akismet.


Pile o'Tags

Stuff I Use

Bitbucket, Debian Linux, Django, Emacs, FreeBSD, Git, jQuery, LaunchBar, macOS, Markdown, Mercurial, Python, S3, SQLite, Sublime Text, xmonad

Spam Report

At least 237143 pieces of comment spam killed since 2008, mostly via Akismet.

Moving the blog to Django

The long-awaited (by me) conversion of this blog to Django is underway. After a couple hours' work I have a full set of models and a functioning admin, and working index and detail views of postings and comments. Searching, posting comments, and tags are the major pieces remaining. Because of my busy schedule I'll only be able to work on it in fits and starts, but I expect the total labor in the end to be about five hours.

I'm curious what the line count of the final product will be. The PHP version, excluding my general-purpose admin class and third-party stuff like Markdown, is about 1000 lines. I'm guessing the linecount of the Django version will be somewhere around a third of that. It's great to see the code melt away, even when it's just single lines getting shorter. For example, this:

$comments = $blog->query("SELECT comments.name, comments.id, posts.title, posts.id FROM
comments, posts WHERE posts.id=comments.post_ref ORDER BY comments.timestamp DESC 

becomes this:

comments = Comment.objects.all().order_by('-timestamp')[:RECENT_COMMENT_LIMIT]

When I started working with Django, one thing I missed from my own PHP admin code was automatic introspection. For example, in my system, this code produces a complete, functioning admin page for editing comments:

include "DB_Edit.class.php";
$admin = new DB_Edit ($DB_PATH, "comments");
$admin->set_summary_cols ("name", "post_ref", "timestamp");  // like Admin.list_display
$admin->set_input_type ("comment", "textarea");
$body = $admin->html;
print $body;  // typically you would include() a template instead of printing

DB_Edit basically assumes everything is input type="text" unless told otherwise. Not a bad default for most apps, and it makes getting going very quick. But over time, because there's no single definition of the model (except for the database itself), model logic ends up getting scattered throughout the code. Django is keeping things much cleaner.

Yay Django for using regex-based URL patterns that easily replace mod_rewrite rules. Yay me for having no public *.php URLs in the current version.

This is a rewrite, not a port. Instead of going through my PHP codebase line by line, I'm building up the new version component by component. With the models in place, there's not much need to refer to the PHP code at all.

More news as it happens.

Monday, April 10th, 2006
+ + + +

0 comments pending approval
Comment from Matisse Enzer , later that day

I especially like the before-and-after comparison - that sort fo thing helps me understand code better than a lot of explanations.

Comment from Dagur , later that day
comments = Comment.objects.all().order_by('-timestamp')[:RECENT_COMMENT_LIMIT]

Just wondering, isn't it possible to limit the number of results without fetching all the objects and slicing?

Comment from Paul , later that day

It's not only possible, but it's already happening in that example -- the db lookups are lazy. See the query.py source for details if you're curious.

Comment from Adrian Holovaty , later that day

Note you don't need the all() there, although it works either way.





You only need the all() if you're not applying any filters.

Comment from Paul , later that day

Thanks, not sure how I made that error. I have the M-R query examples taped to my desk!

Got tags working today. Getting closer...

Comment from dp_wiz , 1 day later

When I started working with Django, one thing I missed from my own PHP admin code was automatic introspection.

Duh! Django's internal admin stuff is really awesome.

Comment from Paul , 1 day later

Indeed it is. But it doesn't to table introspection on the fly. As I said, Django's approach is ultimately cleaner.

Comment from dp_wiz , 1 day later

you can take introspection code from django-admin.

Comment from Paul , 2 days later

Perhaps I'm not being clear. I don't want to change the way Django works!

Comment from Andrew , 3 days later

Will your code be available? I'm curious as to how you're doing tagging. I've implemented a very craptastic way to do it for my blog (though i haven't put it up yet), but really don't like my solution to it. Glad to see you moving this to django.

Comment from Paul , 4 days later

Funny you should mention tagging -- that's the one part of my original model that I've decided really needs to change. Django makes it so easy to do many-to-many relations that I can do it right, instead of carrying over the (surprisingly functional) space-delimited-text hack that I'm using now. Having a real tag model will make it easier to reimplement the current features and to add new ones.

I may use Hugo's tagging code.

I do plan to release the source, but I'm so busy with work that the whole thing's going in slow-motion right now.

Comment from Matthias , 4 weeks later

Yay, an open-source Django blog! Can't wait.

Comments are closed for this post. But I welcome questions/comments via email or Twitter.