Category Archives: LinuxLaboratory

New Job, Car, Baby, and Other News

New Baby!

I know this is my geek blog, but geeks have kids too, so first I want to announce the birth of our second daughter, Sadie, who was born on September 15th. She’s now over a month old. This is the first time I’ve stayed up late enough to blog about her. Everyone is healthy, if slightly sleep-deprived :)

New Job!

The day before Sadie’s birth, I got a call with an offer for a job. A *full-time* job, as a Senior Operations Developer for MyYearbook.com. After learning about the cool and very geeky things going on at MyYearbook during the interview process, I couldn’t turn it down. I started on October 5, and it’s been a blast digging into all of the cool stuff going on there. While I’m certainly doing my fair share of PHP code review, maintenance, and general coding, I’m also getting plenty of hours in working out the Python side of my brain. I’m finding that while it’s easier switching gears than I had anticipated, I do make some really funny minor syntax errors, like using dot notation to access object attributes in PHP ;-P

What I find super exciting is something that might turn some peoples’ stomachs: at the end of my first week, I sat back and looked at my monitors to find roughly 15 tabs in Firefox open to pages explaining various tools I’d never gotten to use, protocols I’ve never heard of, etc. I had my laptop and desktop both configured with 2 virtual machines for testing and playing with new stuff. I had something north of 25 terminal windows open, and 8 files open in Komodo Edit.

Now THAT, THAT is FUN!

The projects I’m working on run the gamut from code cleanups that nobody else has had time to do (a good tool for getting my brain wrapped around various parts of the code base), to working on scalability solutions and new offerings involving my background in coding *and* system administration. It’s like someone cherry-picked a Bay Area startup and dropped it randomly 30 minutes from my house.

My own business is officially “not taking new clients”. I have some regular clients that I still do work for, so my “regulars” are still being served, but they’ve all been put on notice that I’m unavailable until the new year.

New Car!

I’m less excited about the new car, really. I used to drive a Jeep Liberty, and I loved it. However, in early September, before Sadie’s arrival, it became clear to me that putting two car seats in that beast wasn’t going to happen. The Jeep is great for drivers, and it has some cargo space. It’s not a great vehicle for passengers, though.

At the same time, I was running a business (this was before the job offer came along), and I was finding myself slightly uncomfortable delivering rather serious business proposals in a well-used 2003 Jeep. So, I needed something that could fit my young family (my oldest is 2 yrs), and that was presentable to clients. So, I got a Lexus ES350.

I like most things about the car, except for the audio system. It seems schizophrenic to me to have like 6 sound ‘zones’ to isolate the audio to certain sets of speakers, but then controls like bass and treble only go from 0 to 5. Huh? And the sound always sounds like it’s lying on the floor for some reason. It’s not at all immersive. The sound system on my Jeep completely kicked ass. I miss it. A lot.

Other News

I’ve submitted an article to Python Magazine about my (relatively) recent work with Django and my (temporarily stalled) overhaul of LinuxLaboratory.org, and my experiences with various learning resources related to Django. If you’re looking to get into Django, it’s probably a good read.

I’ve been getting into some areas of Python that were previously dark, dusty corners, so hopefully I’ll be writing more about Python here, because writing about something helps me to solidify things in my own brain. Short of that, it serves as a future reference point in case it didn’t get solidified enough :)

My sister launched The Dance Jones, a blog where she talks about fitness, balance, dance, and stuff I should probably pay much more attention to (I’m close to declaring war on my gut). Also, if you ever wanted to know how to shoulder shimmy (and who hasn’t wanted to do that?), you should check it out :)

Django App Design: Extend or Build From Scratch?

Django has proven itself (to me, anyway) as a great tool for the job of creating very robust web applications with lightning speed. In just a week or two, I’ve created a site that encompasses a blog with an akismet-powered comment moderation system, a code sharing section complete with highlighted code segments (and line numbers), and I have a way to create static HTML pages and map them to whatever URL I want. Behind all of this is an administrative area where I can add/edit/delete any type of content hosted on the site, add users, put them in groups, and even create new sites, and map content to the different sites. It’s pretty powerful.

One thing I really like about Django is that it lets you be sort of a commitment-phobe, and actually rewards you for it. If you’re not sure which direction you want to go in with a given feature, just make it as generic as possible. Not sure which URL you want some content to show up at? No problem — edit a line in the project’s URLConf, and it’s somewhere else now. Need to redo that sidebar menu to pull in content from a completely new app? No problem. Edit a template with a couple of new tags, delete some others, and if you’ve set up inheritance properly, that’s it. Done. Decided you want users to be logged in to see some content? Multiple ways to do that – edit the view, edit the template… easy, easy, easy.

And did I say powerful?

However, with great power, of course, comes great responsibility. One thing I don’t want to do is create some monstrosity of code with tightly-coupled entities, because that takes away my ability to be non-commital and make on-the-fly changes with the greatest of ease. As it turns out, being non-commital takes a bit of thought, and a bit of work.

So here’s the deal…

I have a blog app which I think is extremely similar to the blog app in Practical Django Projects, 2nd Edition. It has an Entry object which has some rather nice features that I think are generically useful regardless of whether this “Entry” happens to be a blog post, an article in a CMS, a code snippet, or whatever. And this is the root of my design dilemma.

I’d like to devote a section of my site to republished articles I’ve written over the years, and new ones I plan to write going forward. Having used Django’s built-in flatpages app for static HTML content, I can already see that it’s really not up to doing double-duty as a CMS. Specifically, it doesn’t have the notion of status, so I can’t mark something “Draft” and come back to it later. It also requires me to put in a URL to create a static mapping between a URL and a flatpage object. Also, flatpage objects don’t have attributes I’d like to have like “Original Publication Date”, “Original Publication URL”, “Last Updated”, etc. There’s no notion of categories, tags, or anything like that, either, which I think could be useful in presenting the list of available articles.

But my blog app has a good bit of that functionality, and my Entry object has a good number of the attributes I want. So where to from here?

Well, I haven’t looked deeply into this, but I know I could subclass Entry, make the one or two changes I’d need, and go that route. Unfortunately, doing this basically means that the CMS isn’t really “standalone”. It depends on my blog app.

The other option is to build the features I want *into* the blog app itself. I haven’t looked deeply into this either, but I don’t think it would be all that difficult to create a way for me to specify at the time I create an “Entry” that this piece of content is a “Blog Post” or an “Article”. However, at that point I’m basically turning my standalone blog app into something that is not just a blog app. If I ever built another site and only wanted a blog, I couldn’t just move my blog app into place and have it. Or… I could, but I’d have all this “Article” cruft hanging around in my admin interface.

This is all not to mention that I’d be breaking a tradition of keeping things small and simple, both to ease debugging, and to ease future development of the small, simple app. Everything becomes more complex. Maybe I’m answering my own question…

What to do?

I’m unsure which way to take it, to be honest. My thinking right now is that I’ll just copy my blog app’s models.py file to my new app, make my changes there in the new app, and ‘syncdb’. Sure, it’s redundant… but it’s only redundant *today*. If I decide later on to add a feature to the blog that makes absolutely no sense for the CMS (or vice versa), I win. If I decide to create a new site that only needs a CMS *or* a blog, I also win.

I’m always open to suggestions and bits of wisdom from folks who’ve been down this road before. If you see big gaping flaws in my logic, let me know. Otherwise, I’m gonna create some short-term redundancy in exchange for some long-term flexibility.

Create a Tagging Index Page with django-tagging

For those not following along, I’ve been recreating LinuxLaboratory.org using Django. It’s my first Django project that you could call “real work”. I’ve been using the Django documentation, various blogs, and the 2nd edition of “Practical Django Projects”, which has given me a lot of ideas, and a lot of actual code. Some of it worked, some of it didn’t, some of it didn’t do things the way I wanted, and some of it was left as an exercise to the user. This was the case with some of the django-tagging-related stuff, which has been broken on the site for a while.

I finally got tired of tagging not working properly on LinuxLaboratory.org, so I started diving into the code and found that one of the things I wanted to do was actually pretty darn easy. In the process, I thought of something else I’ll probably implement later as well. Not *all* of my problems are solved, but I’m on my way!

So, Linuxlaboratory is made up of three different sections: a blog, which is its own app, a “Code” area which is another separate app, and a content management system (flatpages right now) that will handle storing republished articles when I get around to importing them all.

I enabled tagging on everything. I’m not solidly in one camp or the other on the whole “Tagging everything is bad” debate. Rather than theorize, I decided to give it a go and see how it does. My guess is that once I add a search box it will rarely actually be used, but what do I know?

The problem this presented me with was trying to figure out a way to present the user with one big monstrosity of an “index lookup” page, which would list all of the tags, and for each tag, list links to anything of any content type that was tagged with it. I understand that this could become unwieldy at some point, but if I need to I suppose I can pretty easily paginate, or present alphabet links, or perhaps both!

Though I understood the potential for future disaster, it still bothered me that I couldn’t find a quick answer to the question, so here it is for those wanting to do something similar with django-tagging. For reference, my tag index page is here.

Template Tags in django-tagging

I had actually started creating a custom template tag, and was looking at the Django docs, which stated “a lot of apps supply custom template tags”. Duh! I cd’d into the tagging directory, and there was a directory called “templatetags”. The tagging_tags.py file inside was pretty well documented, and the tag I was about to write myself is called ‘tagged_objects’. Here’s the docstring for that tag:

“””
Retrieves a list of instances of a given model which are tagged with
a given “Tag“ and stores them in a context variable.

Usage::

{% tagged_objects [tag] in [model] as [varname] %}

The model is specified in “[appname].[modelname]“ format.

The tag must be an instance of a “Tag“, not the name of a tag.

Example::

{% tagged_objects comedy_tag in tv.Show as comedies %}

“””

Perfect. I already had a tag_list.html template (which, if memory serves, is one of the things left as an exercise to the user in Practical Django Projects), and it listed the tags in use on the site, but instead of linking off to a ‘tag_detail’ page for each tag, I envisioned something more interesting. I’m not there yet, but this index page is step one.

Putting Together a Template

What I needed to do was simply {% load tagging_tags %}, and then call the {% tagged_objects %} tag with the proper arguments, which consist of a tag *object* (not a tag name), the model you want to grab instances of, and a variable name you want to store the instance in. Here’s the content block from my tag_list.html:

{% block content %}
{% for tag in object_list %}
<div id="entry">
   <p>{{ tag.name }}</p>
   <ul>   {% load tagging_tags %}
      {% tagged_objects tag in  monk.Entry as taggedentries %}
      {% for entry in taggedentries %}
         <li><a href="{{ entry.get_absolute_url }}">{{ entry.title }}</a></li>
      {% endfor %}
      {% tagged_objects tag in ray.Snippet as taggedsnippets %}
      {% for snippet in taggedsnippets %}
         <li><a href="{{ snippet.get_absolute_url }}">{{snippet.title}}</a></li>
      {% endfor %}
   </ul>
</div>
{% endfor %}
{% endblock %}

So, the view I’m using supplies Tag objects in a variable called object_list. For each Tag object, I spit out the name of the tag. Underneath that on the page, for each tag, there’s an unordered list. The list items are the Entries from my “monk” application, and my Snippets from my “ray” application. I hope reading this template along with the bit above from the docstring for the template tag helps someone out. And check out the other tags in tagging_tags.py as well!

Rome Wasn’t Built in a Day

Of course, there’s still an issue with my particular implementation. Tagging was originally implemented specifically for the entries in the “/weblog/” part of my site. However, now that they’ve been applied to things in the “/snippets/” part of my site, this page doesn’t *really* belong in either one. However, if you go to the page, you’ll see that the “Blog” tab in the navigation bar is still highlighted. I’ll figure out what to do with that at some point. Until then, enjoy, and if you have any input or wisdom to share, please leave comments! Also, you should follow me on twitter!


	

My Django Project Update: RSS Feed, “Home” Link, and more.

In continuing the rebuild of LinuxLaboratory.org using Django, I’m happy to say that things have moved fairly smoothly. I’m using a good mix at this point of stuff from the 2nd edition of “Practical Django Projects”, the Django documentation, blog posts, and docs from other apps I’m making use of.

RSS

I said in one of my previous posts that I’d wait until I burned my feed before giving out the link, and I just did that, so if you want to subscribe to the LinuxLaboratory Blog feed, here’s the link to do that. Right now there’s just one feed for all of the blog entries, but since I post almost all of my really geeky stuff here, the LLO Blog will be mostly site updates like new articles, code, or features being added. The LLO Blog isn’t something that’s intended to get tons of traffic or have tons of posts all the time. The meat of the site will be the content management system which houses articles, and the “Snippets” area which will house scripts and hacks and stuff.

The “Home” Link in Django

I’m not sure why, but it took me a little time to figure out how to link to the base site in a Django template. I had some URL routing set up such that, well… here’s what I have:

In the main project’s urls.py:

(r'^$', include('monk.urls.entries'))

I named my blog app “monk”, after Thelonius Monk. There’s actually a reason I picked his name for a blog app, but it’s not important right now (though, for a chuckle, I picked his last name because his first name breaks a long-standing “8 character” tradition in UNIX).

Anyway, in the corresponding URLConf in monk, I have:

(r'^$', 'archive_index', entry_latest_dict, 'monk_entry_archive_index')

And then in one of my base templates I had this (which is perfectly valid code):

<a href="{% url 'monk_entry_archive_index'}">LinuxLaboratory.org</a>

The ‘{% url %}’ tag can take a URLConf name as an argument, and it’ll do a reverse lookup to get the URL, which is nice, except that this would always land people at “http://linuxlaboratory.org/weblog”, and I wanted them to just go to the base URL for the site. The canonical home page. The root URL. Whatever you want to call it.

There are multiple ways to link back to the base domain from within a template, but I’m not sure if there’s a canonical, “Django-sanctioned” method. You can just make an href pointing to “/”, you can hard-code the whole URL, and I found that doing “href={{ settings.SITE_ID }}” also worked just fine. I tried that last one after discovering that the base URL for the site isn’t in settings.py, and reading that SITE_ID was used by some applications to help them figure out their own URL routing. SITE_ID is a numeric value that represents, according to the Django docs, “the current site in the django_site database table”.

That’s a little confusing, but if you just have a look at the table, it starts to become clear how this could work:

mysql> select * from django_site; 
+----+---------------------+---------------------+
| id | domain              | name                |
+----+---------------------+---------------------+
|  1 | linuxlaboratory.org | linuxlaboratory.org | 
+----+---------------------+---------------------+

It seems logical that using {{ settings.SITE_ID }} in a template could cause the right things to happen, but I haven’t gone diving into the source code I’d need to to prove that it does.

What’s the canonical way of doing this?

Up Next…

So, I have what I think will be a decent setup for code sharing (complete with highlighted syntax), a solid foundation for a blog app, and I’m working on the content management system. I’m using TinyMCE in the admin interface to edit blog posts as well as the CMS content. I’ve got very very basic CSS in place. The basics are here. Now what?

Well, first I need to get my ducks in a row. This includes:

  • Stabilizing a proper development and deployment workflow. There’s a rather nice setup over here, and the 2nd edition of Practical Django Projects has also been enlightening in this regard.
  • Cleaning up my templates. I created the Blog app first, and so of course now I have like 3 separate apps, and I don’t really want them all to have a different look and feel, so I need to abstract some bits and perhaps create a “/templates/common/” directory that will be referenced by all of the apps in the project…? How do you do it?
  • I’d like to get some high-level navigation horizontally across the top instead of having those links in the sidebar. I don’t want fancy popout menus — just a very simple bar where the nav links basically just represent the functions of the different apps: Blog, Articles (CMS), Code, and maybe an About link or something.
  • And more!!

After that stuff is out of the way I’ll start thinking about some new features:

  • I’d like to be able to include images (maybe multiple images) in various types of content. In fact, perhaps all kinds of content. Screenshots for the code snippets, stock images for CMS and blog content, etc. I’m a little intimidated by this because I know my web host (webfaction) limits the amount of memory I can use at any given time. I guess I can just manually scp images to my static media location and link them into the content, but it doesn’t seem ideal. Ideally I can upload them in the same interface where I edit the content, and maybe have the img src tag associated with the instance of the model I’m editing in the database. Does something do this already?
  • I’d really like to have a wordpress-style “Stats” page. Actually, I’d like to have a much better stats page than the wordpress one, but that’d be a start. The stats page I’d actually *like* to have is best described by Marty Allchin here (2 years ago. Anyone know of an app that is aiming for anything close to that?)
  • RSS feeds for the code snippets section (this should be simple)
  • On-the-fly PDF generation for downloading the PDF version of… whatever. A code snippet, an article… Haven’t even investigated this yet.
  • I really, really, really, really want to turn my geek conference calendar into a google maps mashup using GeoDjango. This is another bit I’m slightly intimidated by, because I didn’t realize GeoDjango was built-in these days, and I started out down this road using MySQL as my database for whatever reason (instead of PostgreSQL, which I actually like better and, as it turns out, has way more mature GIS functionality).
  • At some point, I’d like to ensure that the old URLs to content that was on the old site will actually still work, and land people on the same content in the new site. The URL layout isn’t actually horrifically different, so hopefully I can get that in place without *too* much fuss. I know Django has a redirection app built-in, but I’m not sure if this is the right way to do it, or if I should just use Apache rewrite rules. Anyone compared the two?

So those are the big goals. Some are simple, others less so, but I hope to complete all of this within the next… well, before the new baby is born, which is going to be some time in the first half of September. Wish me luck (on both), and please share your tips on how I might accomplish any of the above goals (I’ve heard all the tips I can handle about kids, thanks).

Django, Pygments, Templates, Code Sharing, and Design

Welcome to the latest update!

I spent a total of about an hour on the “Social Code Sharing” application in the 2nd edition of “Practical Django Projects”, and I’m not completely finished with it, but I’ve got syntax highlighting and the basics covered. I can add, edit, and delete snippets, list snippets, and show a particular snippet, complete with syntax highlighting. In an hour. That’s pretty ok, considering I spent a lot of that time debugging what I would call, at best, an unexplained inconsistency in the book that caused me to run into a series of errors before finally figuring out the right way to do it (it’ll all be in the book review – stay tuned for that).

I don’t have links or user contribution set up yet. I only have a quick example up right now, which you can see here, which brings me to the design question: I want my navigation sidebar on the right, but I really don’t want the code to overlap it in any way. I’m kinda wondering if there’s an elegant way to fix that. I considered moving the sidebar to the left, but didn’t want to do that. I considered just making the main content area bigger, but then I’m just guessing, and praying that it fixes the problem for all future code snippets. What’s there now is just a CSS-based solution that creates a scrollable area for the code if it’s too long. Maybe this will suffice (though I have some CSSing to do to refine what’s currently there — the entire content area scrolls right now!)

Since there’s no example template for dealing with code highlighting in the book, and the downloadable code only goes through the first app in the book (the CMS app), here’s the template I’m using for the snippet_detail.hml file:

{% block title %}{{block.super}} | Random hacks{% endblock %}
{% block extrahead %}
<link rel="stylesheet" type="text/css" href="/static_media/llo_main/css/pygments.css" />
{% endblock %}
{% block content %}

 <ul>
 <li>{{ object.title }}</li>
 <li>Published: {{ object.pub_date }} Updated: {{ object.updated_date }}</li>
 <li>Language: {{ object.language }}</li>
 <li>Author: {{ object.author }}</li>
{% load markup %}
 <li>Description: {{ object.description_html|markdown }}</li>
 </ul>

<p>
{{ object.highlighted_code|markdown }}
{% endblock %}

Your CSS path will be different, in all likelihood, and there are some touches missing, like use of a variable to make the title bar dynamic and stuff, but right now I’m shooting for function — the form will come later.

For the snippet_list.html file, I found that what’s in the book just doesn’t work at all. It uses pagination using Django’s built-in pagination capabilities, but the small subset of a template that’s provided references a {{ page }} variable, which does nothing. The Paginator class appears to make individual pages available to templates in a variable you’d reference as {{ page_obj }}, not {{ page }}. Referencing {{ page_obj }} by itself (without referencing any attribute of it) results in output that says something like “<Page 1 of 1>”.

It’s not necessarily pretty to have those “< >” around the edges of the output, and it’s not necessary to use this method of getting the page number and the page count. The page number is available as an attribute of the page class, and the total number of pages is available from the associated paginator object’s ‘num_pages’ method, which you can grab via {{ page_obj.paginator.num_pages }}. You can see my snippets_list.html output here, and here’s my template (at time of writing – note that my site is a work in progress and can change without warning):

{% block content %}

<p>Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</p>
<p>
{% if page_obj.has_previous %}
<a href="?page={{page_obj.previous_page_number}}">Previous page</a>
{% endif %}
{% if page_obj.has_next_page %}
<a href="?page={{ page_obj.next_page_number }}">Next page</a>
{% endif %}</p>

{% for snippet in object_list %}
 <ul>
 <li><a href="{{snippet.get_absolute_url}}">Title: {{ snippet.title }}</a></li>
 <li>Published: {{ snippet.pub_date }} Updated: {{ snippet.updated_date }}</li>
 <li>Language: {{ snippet.language }}</li>
 <li>Author: {{ snippet.author }}</li>
 <li>Description: {{ snippet.description_html }}</li>
 </ul>
{% endfor %}

{% endblock %}

In the interest of full disclosure, I should also say that, at time of writing, I haven’t added enough snippets to fully test the previous and next page links. I’ll get there, I’m sure — especially when I get user contributions in place, which will happen when I feel a little more confident that this is going to happen in a secure manner. Having been to PHP land, it’s a little unnatural for me to trust the code that comes with a framework to do things properly, which my sysadmin brain always parses as “securely, and in a functionally correct manner”.

Please share tips in the comments! That’s the update for now — stay tuned for more as the recreation of LinuxLaboratory.org continues to unfold.

Django RSS Feed Finally Working

Ok, so now LinuxLaboratory has the following features working:

  • comments (along with comment moderation and akismet support),
  • a WYSIWYG editor for my posts
  • markdown support for comments
  • email notification of errors and new comments
  • a full-blown administration interface that lets me deal with any apps, users, or content on my site,
  • some cheesy CSS (hey, it’s better than black-on-white, at least IMHO)
  • an RSS feed
  • sidebar content that includes information about the current content, and links to other recent content on the site.
  • Maybe some other stuff I’ve forgotten. It’s late.

There’s only one RSS feed available at the moment, and I’m not linking to it because the URL will likely change and then I’ll have people all pissed at me, or worse, not subscribed to the feed. I’ll set up FeedBurner on it and post that URL when I get it set up. This way, if my feed URL changes, I can change it in the FeedBurner setup, and everyone else just subscribes using the FeedBurner URL. Handy.

I’m veering away from the book for some of this stuff. For those who weren’t following along, this is all being done with Django, and I’ve been using the 2nd Edition of Practical Django Projects to help me along both in getting this thing built, and in learning more about Django. I use Python for everything else — why not the web?

Anyway, I’m jumping around the book at this point, taking bits from various parts of the first 7 chapters, checking out the official django docs, looking at lots and lots of articles on blogs all over the place, and putting things together the way I want them. For now, I just want a stupid-dumb RSS feed. I’ll get to doing category-specific feeds and Atom feeds later (I also want comment feeds, and one of those cool things that links tweets about the post into the comment thread and stuff).

For now, I also just want a blog, and I’ll get to the CMS later. In fact, through the building of the blog application I’ve become pretty confident, so I’ll probably grab bits from the CMS and the Code Sharing application in the book and put something together that makes sense for my needs.

LinuxLaboratory => Django – Now with Comments, Akismet, and 404.html

I stayed up a little late last night, because I wanted to get comments working on Linuxlaboratory.org. Comments *are* working, and I *do* get email notification of new comments, which is nice. Akismet is installed, and is no longer throwing errors, but to be honest, I’m not quite sure how to test it. I tried creating a comment that looked like spam, but it got posted publicly anyway. I’ll have to figure out how to log the Akismet processing operations and results.

I also set up email notification not just for comments, but for errors. And once I did that, I started getting slammed with emails. There’s a setting you can use to avoid being emailed for 404 (File Not Found) errors, but the problem I had was that, for every 404 error, there was also a TemplateNotFound error, because there was no 404.html file anywhere. So I created a 404.html file. It extends my base template, so it looks like the rest of the site, complete with the sidebar and stuff, and just has a note letting the user know what happened. This is nice because it’s an opportunity to rescue the user’s session by providing lots of links back to the home page, or to other content on the site. I haven’t gotten to it in the book yet (for those just tuning in, the site is being built in part using the 2nd Edition of “Practical Django Projects”).

Next up is RSS feeds. Once that works I might break from the book, because in the course of looking around and setting things up, I’m discovering that there’s a good bit of functionality I’d like to use, more apps I’d like to plug in, and a couple I’d like to write. I’d also like to put a horizontal navigation bar and make an “Articles” section of the site using a CMS, and have it be separate from the “Blog” part of the site. Then I’ll make a “Tools” section and start coding my own versions of tools like subnet calculators and a “CLI Hacks” application which will let me post one-liners I’ve found useful (kinda like commandlinefu.com).

Who knows what else — but first things first. RSS!

“Practial Django Projects”, Custom Template Tags, and Updates on LinuxLaboratory

Hi all,

If you’ve not been following along, I’ve picked up the 2nd edition of Practical Django Projects, and am using it to help me reinvent LinuxLaboratory.org (LLO). Though LLO is really a documentation site where I republish articles I’ve written for Linux.com, O’Reilly, and others over the past 10 years, I started out by putting a blog application in place as a way for me to communicate with people interested in how LLO is being built. Once I get comments and RSS in place, it will serve that purpose much more effectively. Until then, I’m putting more updates here than there.

So let’s have a look at what I’ve gotten done so far, and the stumbling blocks I’ve run into.

Look and Feel

Just looking at the blog application in its current form, you can see that I’ve done a thing or two to customize the look and feel so it’s not just plain black text on a white background. I added a simple CSS stylesheet that puts the sidebar where it should be, and updates the font in use. If you’re not using IE, you can probably also see a thin dotted line around the entries and the sidebar. This is probably temporary, and helps me quickly debug CSS issues I’m likely to come across early on (I’m not a hardcore designer, if you couldn’t tell). The accomplishment there was understanding my web host’s setup enough to ensure that static files like CSS stylesheets are served by the “main” Apache instance, and not my private instance which is hosting my Django application. This helps keep memory consumption down, and keeps things moving quickly.

Here’s a shot to give you an idea of the current overall look and feel. DISCLAIMER: It’s not impressive.

llo_mainviewIt’s brown. I like brown, and there aren’t tons of brown sites everywhere. I’ll likely change things as I move forward, because I also have a logo for the site and some other ideas and such. I also have aspirations beyond just a blog and CMS site. I’m going to add applications that actually do stuff, in part just to see if I can, in part because I’ll use them, and in part because others might find them useful. For example, I’ll be adding a subnet calculator, and a bandwidth delay product calculator.

The Sidebar: Entries, Categories, Links, and Maybe Tags

First, you should know that what appears on any given page of a Django site, along with what it looks like, the content it holds, and any other attribute can be modified/dynamic/etc for each page of the site without reproducing a whole bunch of code. Django gives you so many shortcuts to use to make this “just happen” that it’s really educational to go through the process of building a Django application, even if you hate Python and refuse to use it for real work. There are lessons to be learned here that you might find useful back in your development platform/framework of choice.

My sidebar right now contains the main “Navigation” links, a “What is this?” entry for each page you land on telling you what you’re looking at, a list of the most recent entries on the blog, and the most recent links posted to the Links section.

The “Recent Links” and “Recent Entries” sections show an interesting bit of Django magic. There are separate tables in the database for Links and Entries, and the fields aren’t all the same in the tables, and yet, I didn’t write one bit of SQL to get the data out, and didn’t write very much code at all to present it. Django supplies a few collections of default “views”, and one collection of them is for presenting data that is “date-based”. Pass in a few parameters to tell it the model (Link or Entry), and the number of recent entries to grab, and it goes off and does it for you.

Believe me, this *does* seem a little confusing at first. Figuring out how an http request is handled, how all of the data is gathered and passed to a template, and then finally rendered, takes a bit of time. Debug enough issues in the development of your first app or two, and you’ll get it cemented in your brain.

The one thing that still doesn’t work right is the ‘Tags” link on the sidebar. In the book, this is implemented using the django-tagging module, which is a third party application. Setting up my first 3rd party app for use with Django was no trouble at all, but I think the book should’ve gone through a bit more hand-holding in dealing with django-tagging. I hit a few glitches in using it at first, but because I had a lot of Django’s basic workings figured out by then, I was able to fix things on my own. Others might not be so lucky.

The django-tagging app’s model doesn’t really look like one I’ve seen so far in my Django travels, and is completely different from the models I created for my blog app. I figured out what was going on, and I have some idea what the path to success will look like for creating the “tag reference” page I’m hoping to build, but I decided that I’d put it aside and move on to dealing with things that are more immediately useful. I rarely if ever use tags on, say, this blog. RSS feeds and comments are in the next chapter, and I really can’t live without those.

Before I moved on to RSS and comments, though, I wanted to understand “custom template tags” in Django, so I went through the end of Chapter 6 and created one, and then created a more generic one to replace the first one. The more generic one (get_latest_content) caused Django to issue 500 errors. The idea of ‘get_latest_content’ is that it’s more generic to create one template tag that can take arguments telling it what “content” is than to create separate template tags for each type of content on the site. Unfortunately, I *believe*, but am not *sure* that there’s actually a bug in Django that makes this not work.

To implement the custom tag, you need to use a method called “get_model”, which I believe is supposed to return an object of type “model”, which will then have an attribute called “_default_manager”. What *actually* happens is it seems to be returning a “unicode” object, which has no such attribute, and Django tells you so.

So, I created separate “get_latest_entries” and “get_latest_links” template tags. Here are my custom template tag definitions:

def do_latest_entries(parser, token):
     return LatestEntriesNode()

class LatestEntriesNode(template.Node):
 def render(self, context):
    context['latest_entries'] = Entry.live.all()[:5]
    return ''

register = template.Library()
register.tag('get_latest_entries', do_latest_entries)

def do_latest_links(parser, token):
  return LatestLinksNode()

class LatestLinksNode(template.Node):
   def render(self, context):
     context['latest_links'] = Link.objects.all()[:5]
     return ''

register.tag('get_latest_links', do_latest_links)

If ‘get_latest_content’ worked, I’d only need to register one tag to do the jobs of both of these tags, but it’s not like this is a horribly difficult bit of code to manage, so it’s a workaround until either I find my typo or Django fixes their bug. This is a rare instance in which I do *not* feel like a workaround for a problem is a hack that’s going to chomp down on my “jewels” later on.

If you run into this issue and decide to go this route, don’t do what I did at first and call “register = template.Library()” for each tag. You create *one* new library, and then register *all* of your tags to it. The book (through Chapter 6 anyway) only has one tag at a time in there, so it’s not covered.

Here’s some code from the part of the template that uses the custom tags:

<h2>Recent Entries</h2>
<ul>
  {% get_latest_entries %}
  {% for entry in latest_entries %}
    <li><a href="{{entry.get_absolute_url}}">{{entry.title}}</a>
posted {{entry.pub_date|timesince}} ago.</li>
  {% endfor %}
</ul> 
<h2>Recent Links</h2>
<ul>
   {% get_latest_links %}
   {% for link in latest_links %}
     <li><a href="{{link.get_absolute_url }}">{{ link.title }}</a>, 
posted {{ link.pub_date|timesince}} ago.</li>
   {% endfor %} 
</ul>

It’s been a lot of text, so here’s another screen shot, this time of my ‘Categories’ page, which I altered a bit from llo_categoriesthe book: I wanted mine to be an index-style listing that shows the category, and all posts in that category, instead of just showing categories and making the user click to see the entries in that category. Chances are the user isn’t really just curious to see what categories exist. Chances are also that some day I’ll be sorry I did it this way because I’ll have so many categories and posts that browsing this page will be cumbersome, but it’s *SO* easy to change it around that I’ll deal with it when I get there.

The Big Win: The Admin Interface

Django fanboys are quick to point out that Django’s admin interface is not just a “battery included”, but rather a “diesel-fueled power generator included”, and I’m inclined to agree. Writing admin interfaces is no fun, in part because end users never see it, so you can’t really show it off. Admin interfaces I’ve seen and written for in-house applications are usually design nightmares, and require some tribal knowledge to use effectively. I applaud the Django folks for doing the best job I’ve seen thus far at automatically creating an admin interface to manage pretty much *every* aspect of the site.

Once I created the data models for links, tags, categories, and entries, I was able to immediately use the admin interface to create new blog entries, add new links, new categories, etc. Of course, I can edit and delete items using the admin interface as well. The admin interface’s goal is to be functional — it doesn’t assume it’s going to be used by folks used to using Microsoft Word, or Emacs for that matter. Input is all just textarea elements, but if you want to you can plug in TinyMCE and give admins a wysiwyg admin interface. The book shows you how to use TinyMCE in its creation of a CMS application. I didn’t do the CMS app, but have downloaded TinyMCE and plan to use it as soon as comments and RSS are working on the blog.

Here’s a shot of the admin interface, which I did just about *nothing* to creatello_admin_entries.

This is, specifically, the part of the admin interface dealing with entries (blog posts). From here I can add a new entry (using that gray button in the top right corner), I can click an existing entry to edit it, or I can check the box next to an entry and choose “delete” from the “Action” drop down menu to delete it. It’s simple, but functional enough that I’d imagine most people using this for their own needs won’t find it necessary to create another one — at least not from scratch. The admin interface *is* customizable.

Apps and Projects

Another reason I started off building the blog app from the book is because it’s a standalone application, and not a project like the CMS, which is the first project in the book. I plan to take this experience with building a standalone application and then go back to build a standalone CMS as well instead of building the CMS as a project, and the blog as an app that can be used by the CMS project. I’m not sure what the logic was in setting the book up that way, but it seems to me (and I could be so, so laughably wrong here) that the project should contain as little code as possible. Preferably none if possible. It should contain URLConfs (and as few of those as possible), and settings.py. Anything else should be decoupled from the project if it’s feasible. Django makes it very easy to decouple URLs and templates and the like, and the community advocates as much decoupling as possible,

In fact, my own blog app is actually a standalone application that lives in its own directory and can be tar’d up and moved elsewhere at the drop of a hat. Django *apps* are linked into a Django *project*, which is what I think of as the “site-specific” collection of settings like database connection info, admin emails, etc. Drop an app in some directory, list it in the “INSTALLED_APPS” setting in your project’s ‘settings.py’ file, and you’re off and running.

Stay Tuned!

I hope to have RSS and Comments enabled on LLO in the next day or so, time allowing. I’m also maintaining my consulting business while I’m doing this, so time isn’t always on my side — speaking of which, I offer discounted consulting rates to work on Python projects, because I really like using Python, and now that I’m making friends with Python on the web, it looks like I might’ve finally achieved the dream of having one language that I can use to do systems development as well as web development. I don’t do much desktop GUI stuff… but who knows?

Until I get RSS and comments up, subscribe to this blog, and follow me (@bkjones) on Twitter.

LinuxLaboratory.org Django Update

Hi all,

So, I’ve begun down the road of reinventing LinuxLaboratory.org using Django. For the moment, I’m mostly starting out using the blog application from the newly released second edition of “Practical Django Projects”, and there’s no CSS or fancy design going on yet, but I have a nice admin interface for creating posts, managing categories and tags, etc., and I’ve created some basic templates that do enough that I can see things working.

I will eventually add all of the old content (mostly system administration and scripting articles I wrote for O’Reilly, Linux.com, and others over the years) back into the site, but I started with the blog so that I could share my progress and (when I enable comments) get feedback and tips as I move along.

There’s no RSS feed yet, either, but that’s coming as well. You can follow along for the moment by just going to the site, or I’ll post short summaries of what’s going on here.

LinuxLaboratory woes, Drupal -> Django?

Ugh…

So, today I tried browsing to one of my sites, linuxlaboratory.org, and found a 403 “Forbidden” error. Calling support, they said it was a “billing issue”. Well, I pay my bills, and I haven’t received any new credit cards, so I’m not sure what that’s about. Further, they haven’t contacted me in any way shape or form at all in a very long time, and I’ve had the same email addresses for years now. Last time they failed to contact me, it was because they were sending all of the mail to “root@localhost” on the web server.

What’s more, the tech support guy, having determined that this wasn’t a technical but an administrative problem, transferred me to a sales person who was not there. I left a message. That was 3 hours ago. So I took matters into my own hands and changed the name server records to my webfaction account, and linuxlaboratory.org now points to an old test version of the site that uses Drupal.

It’s Over Between Us…

Drupal holds the record for the CMS that has run LinuxLaboratory the longest. Since its launch in 2001, LinuxLaboratory has used all of the major, and some of the minor open source PHP CMSes. Drupal gave me something very close to what I wanted, out of the box. Nowadays, Drupal is even nicer since they redid some of the back end APIs and attracted theme and module developers to the project. I’ve even done some coding in Drupal myself, and have to say that it really is a breeze.

But the problem is this: I’m a consultant, trainer, and author/editor. I am an experienced system admin, database admin, and infrastructure architect who makes a living solving other peoples’ problems. I really can’t afford to have something that is super high overhead to maintain running my sites. With Drupal releasing new versions with major security fixes once per month on average, and no automated update mechanism (and no built-in automated backup either), it becomes pretty cumbersome just to keep it updated.

This is in addition to my experiences trying to do e-commerce with Drupal. I tried to use one plugin, but soon found myself in dependency hell — a situation I’m not used to being in unless I’m on a command line somewhere. So, out with Drupal. I know it well and I’m sure I’ll find a use for it somewhere in my travels, but not now, and not for this.

Is Django the Future of LinuxLaboratory?

So I’m thinking of giving Django another shot. In fact, I thought I might try something new and interesting. Maybe I’ll build my Django app right in front of everyone, so that anyone who is interested can follow along, and so people can give me feedback and tips along the way. It also lets me share with people who have questions about a feature I’m implementing or something like that.

For fanboys of <insert technology here>, know this: I’m a technology whore. I consume technology like some people consume oxygen. I love technology, and I get on kicks, and every now and then, a “kick” turns into a more permanent part of my tool chest. Python is one such example. I’ve done lots with Python, but have never really made friends with it for web development. I got a webfaction account specifically because they support Python (and Django). I’ve done nothing with it. Now I think I might.

But not to worry! I own lots of domains that are sitting idle right now, and I’m considering doing a Ruby on Rails app for one of them, and I’m dying to do more with Lua. There’s only so much time!

Webfaction Django Users: Advice Hereby Solicited

So if you’re a webfaction customer using Django, please share your tips with me about the best way to deploy it. I’ve used nothing but PHP apps so far, and found that rather than use the one-click installs webfaction provides, it’s a lot easier to just choose the generic “CGI/PHP” app type and install the code myself. This allows me to, for example, install and update wordpress using SVN. Is Django a similar story, or does webfaction actually have an auto-upgrade mechanism for this? How are you keeping Django up to date?

Thanks!