A Noob In King Guido's Court
Here I am, somehow, impossibly, in Chicago and attending PyCon.
Somewhere in this crowd are other Djangonauts. I need to figure out how to find them.
Mar
27

Here I am, somehow, impossibly, in Chicago and attending PyCon.
Somewhere in this crowd are other Djangonauts. I need to figure out how to find them.
Jan
3

Friends, I have come to an impasse.
There's a reason why I still don't have image embedding up on the site. Read on and help me!
Dec
23

Dig back into my vast blog archive and you will find this post: I said it, I did it. Therein you will find my bumbling, ham-fisted solution for integrating pygment code highlighting into markdown.
I just wandered back past this code today and then stumbled across the actual right way to do this.
Dec
11

Anyone attempting to dip into my modest archive this morning would have seen an error message instead.
I discovered a bug in how my archive_month view was working and I fixed it. And in the process I opened a much worse bug. This is one of the classic narratives, along with "boy meets girl", "stranger comes to town" and the rest.
Let me tell you all about it...
Dec
11

I have all these cool ideas for how this blog is going to knock the socks off of sliced bread, or at least, all things since sliced bread. But to get there, I keep stumbling over all this pesky functionality I don't have.
In a way it's one big lesson in project management. All the little, round-down-to-zero-time tasks add up to an alarmingly non-zero number.
Today's addition is a public checkbox on the BlogPost object. That, plus the custom manager that goes with it. Plus the updates to the views. Plus the test to make sure it works. Plus the Django Evolution code.
Read on for more! I've got some racy opinions on custom managers in here that you won't want to miss!
Dec
9

This is my post for showing off how the sun gets rendered during evening twilight. I am tweaking the publish date a bit because I -ahem- forgot to post this a little earlier.
Dec
9

This is the nerdiest, least useful thing I've added to this site so far: an analog clock renderer!
Check it out: you get a regular clock with an hour hand and a minute hand, but you also get a sun indicator, to help you tell AM from PM. When it's daylight, the sun travels through the sky in nice happy yellow. When it's night time the sun travels around the lower half of the circle and gets drawn a dark blue. The extra fun part is that if it's near sunrise or sunset, the sun's colour is drawn from a gradient between the noon-day yellow and a bright red. I'll have to make a point of posting at dusk tomorrow.
I have no idea if this technique for representing time is at all intuitive, but I really enjoyed making it.
Dec
8

My friends, I have something exciting (and completely unnecessary) in the works.
To pave the way for all the stuff I want to say about that, I've added previewing to my blog.
Let me tell you all about it, below the fold.
Dec
7

I'm using Django Evolution with this project because I knew I would need to muck with my models at some point. Ladies and gentlemen, that point has come!
In order to get categories set up I had to add a foreign key to the Category model from my BlogPost model. I've used the "./manage.py --hint" → "./manage.py --hint --execute" pattern before in other projects, but I decided to use Django Evolution's "Stored Evolutions" feature this time. It turned out to be painless, and I think i could smell rose petals and the absence of stress.
I ran ./manage.py --hint
I copied the lines between the "---------" bits into a file inside blog/evolutions. That looks like this:
from django_evolution.mutations import *
from django.db import models
MUTATIONS = [
AddField('BlogPost', 'category', models.ForeignKey, null=True, related_model='blog.Category')
]
I also created a __init__.py file in there.
__init__ file:
SEQUENCE = ['add_category_fk']
./manage.py evolve.This is a simple case, I know, but this was still a lot easier than firing up psql. A tool that only helps with the easy 80% of the cases is still a useful tool, I think.
Dec
7

Good evening, world!
I have been wracked by horrible guilt this past week, knowing that my new, youthful blog was lying fallow.
Here I am, making amends!
I've added categories to my blog. I now have the ability to separate my developer nonsense from my "personal" nonsense. (Note: "Personal" here is used not to mean "private" but rather, "less interesting to others".) I've also added category-based news feeds. Just go to the category page and subscribe to the feed from there.
Adding categories required new code in a bunch of places. It's not all very interesting. I split my blog post list displaying template code out into a sub-template called "_blogpost_list.html", because I'm using it in a few different templates now, but the code's basically the same.
I did create two new template tags. One is the archive nav code I had earlier, refactored:
@register.inclusion_tag('blog/_archive_nav.html')
def archive_nav(month=None, category=None):
queryset = BlogPost.objects.all()
if category:
queryset = queryset.filter(category=category)
return {'category': category,
'active_month': month,
'month_list': queryset.dates('pub_date', 'month')[::-1]
}
With the new archive nav code, I'm giving up on using the date_list object that the date-based generic views provide. date_list only lists the years that contain content. I was using a little template filter that would take a date representing a year, and return a list of all months with content in that year. It worked great when I always wanted to examine all the content, but it became a nuisance when I sometimes wanted to restrict it to only those blog posts that were in a certain category. I could have fiddled some more with the filter but I decided it would be tidier to write a complete template tag instead and leave date_list behind.
Here's the template:
<ul class="nav-bar">
<li>Archive: </li>
{% for month_date in month_list %}
<li{% ifequal month_date.date active_month %} class="active"{% endifequal %}>
{% with month_date|date:"F" as month_str %}
{% if category %}
<a href="{% url category_archive_month category_slug=category.slug,year=month_date.year,month=month_str.lower %}">
{{ month_str }} {{ month_date.year }}
</a>
{% else %}
<a href="{% url blog_archive_month year=month_date.year,month=month_str.lower %}">
{{ month_str }} {{ month_date.year }}
</a>
{% endif %}
{% endwith %}
</li>
{% endfor %}
</ul>
I discovered something new when I was updating my other templates to use archive_nav properly: Django templates don't support the "None" keyword. When I'm loading the archive nav inside the category detail page I need to pass the category, but I don't have an active month to pass. Here's what I settled on:
{% archive_nav "" category %}
It seems like there ought to be a nicer way to do this, but keyword arguments don't work with simple or inclusion tags and I can't use None.
Anyway, at the end of the day, we're left with an exciting new feature that every other blog already had without even thinking about it. I've got some great ideas on rotating, circular vehicle conveyance tools, as well.
Nov
29

I was gearing up to lay down some TDD on a simple comment e-mailing tool. Then, as I was flipping open the Django source to check something, I noticed a "feeds" module in the comments app. I aspire to Larry Wall's three cardinal virtues of the programmer and a news feed of comments sounds at least as useful as a comment e-mailer, and it had the virtue of already existing, right there in Django.
Ah, but then I noticed: What comments gives you is an RSS news feed. Ahem. I'm cultivating a refined sense of snobbery and hating on MySQL is only the beginning. It has to be Atom or nothing. Don't worry; this time I kept things pretty DRY:
class LatestCommentsAtomFeed(LatestCommentFeed):
def subtitle(self):
return self.description()
feed_type = Atom1Feed
def item_author_name(self, item):
return item.name
All I did was set the feed type and make the subtitle field stand in for the description field. And hey, I figured since we have a name field in the comment, we may as well use it as the author name for each item. I expect there's some obvious reason why I wouldn't want to do this, but in my minimal, unscientific testing with Net News Wire, it seems to work fine.
I don't know where to embed a link to something of as questionable interest as a comments-only news feed. Well, maybe I do. Here you go.
Nov
29

I just wanted to note something neat.
When I was setting up my flatpage template last night I realized I could run template filters on the two strings, flatpage,title and flatpage.content. So now, instead of having to embed raw HTML in my flatpage entry like a brutish savage, I can enter pure, clean-burning markdown and just pipe it through the parser in the template.
Here's the flatpages/default.html template:
{% extends "base.html" %}
{% load markup %}
{% block title %}{{ block.super }} - {{ flatpage.title }}{% endblock %}
{% block content %}
<h1>{{ flatpage.title }}</h1>
{{ flatpage.content|markdown }}
{% endblock %}
Funny side note: I actually felt shamed into editing this template to conform to Eric Holscher's Gentleman's Agreemant on Django Templates
Nov
28

Hey, y'all.
As soon as I got home today i set to work getting commenting working. And sure enough, a mere four hours later, here we are! I haven't changed much from the out-of-the-box django commenting solution, so I'm hoping it just purrs along.
I also added an about page so you can learn some unhelpful trivia about me. Click on my name to get there.
Nov
27

Eric Florenzano (A Django Wizard) has instigated a meme (Update: Now with URL back to his post. Guh. I'm a yutz.):
Rules:
The List:
Yes, friends, that's right. I did it in Django. But not only that, I did it in one file in Django.
Dig it:
{# #} {% comment %}
}
from django import forms
from django.conf.urls.defaults import *
from django.http import HttpResponse
from django.template.loader import render_to_string
DEBUG = True
TEMPLATE_DEBUG = DEBUG
DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = ':memory:'
TEMPLATE_DIRS = (
'./',
)
ROOT_URLCONF = 'settings'
class NameAgeForm(forms.Form):
name = forms.CharField()
age = forms.IntegerField()
def view(request):
if 'name' in request.GET:
form = NameAgeForm(request.GET)
if form.is_valid():
name = form.cleaned_data['name']
ages = range(1, form.cleaned_data['age'] + 1)
else:
form = NameAgeForm()
return HttpResponse(render_to_string('settings.py', locals()))
urlpatterns = patterns('',
(r'^$', view),
)
INSTALLED_APPS = ()
# {% endcomment %} <html><head><title>The Age Machine</title></head><body>{% if name and ages %} {% comment %}
# {% endcomment %} <ul>{% for age in ages %}<li>{{ age }} - Hello {{ name }}</li>{% endfor %}</ul> {% comment %}
# {% endcomment %} <form action="/"><input type="submit" value="Reset" /></form> {% comment %}
# {% endcomment %} {% else %}<form method="GET" action="/">{{ form.as_p }}<input type="submit" /></form> {% endif %}</body></html>
To run it, just put this code in a file called settings.py and run:
django-admin.py runserver --settings="settings"
I managed to get everything crammed into the settings file, and then I made the settings file double as the template. You're either going to be really impressed or really angry. Let me know, either way.
sam - at - pocketuniverse.ca
Nov
27

The source code in the last post is probably too wide for your browser window and the blog post window isn't expanding properly. And, if you have a horizontal scroll bar and use it, you'll see the blog post design disconnect from the background. (Update: Fixed. I told the pre elements to apply scroll bars to text not content to be bound by the requirements of reasonable width.)
Not pretty.
It looks like I'll have to make this a tiling, scrolling background after all. Boo.
This is why it's better to have other people around who can take care of all this HTML and CSS.