Up until a few days ago, my Django blog application was violating DRY. Well, let's be honest, it probably still is, but this one was a blatant violation. What happened was that I wanted to be able to add users to my system without necessarily having them listed as bloggers, since I'm hoping to provide, in the future, gallery, mail and other miscellaneous services to the extended Kulleen clan.
To solve that I created a Person class which had a foreign key into Django's own user class, plus some extra fields. Two of those fields were first_name and last_name, so that meant that for each blogger, I had to enter their names twice. Silliness, I tell you!
Now, I'd read James' article about extending the User model late last year, during the early stages of my django learnings. And to be honest, I didn't really understand the implications.
All of a sudden, two days ago, it hit me! So, I made a few changes to my blog to make use of that technique. My code went from this:
class Person( models.Model ):
first_name = models.CharField (maxlength = 100)
last_name = models.CharField (maxlength = 100)
user = models.ForeignKey (
User,
verbose_name="Associated admin user",
null=True,
blank=True
)
photo = models.ImageField(upload_to = 'photos')
blogger = models.BooleanField(default = False)
to this, instead (getting rid of the Person model entirely in the process):
class UserProfile( models.Model ):
blogger = models.BooleanField (default=False, core=True)
photo = models.ImageField (upload_to='photos', blank=True, null=True)
user = models.ForeignKey(User, unique=True, edit_inline=models.TABULAR, num_in_admin=1,
min_num_in_admin=1, max_num_in_admin=1, num_extra_on_change=0)
The other advantage is that now all the user information is in one place in the admin interface, instead of two.
I did have to alter some of my templates and one of my templatetags a bit to make use of the new code, but it was mostly improvements like the transition from entry.author.user.username to entry.author.username which is less indirection.
So the basics of my weblog model, then, are:
class Entry( models.Model ):
# Basic info
author = models.ForeignKey(User)
title = models.CharField(maxlength=200)
slug = models.SlugField(prepopulate_from=('title',))
tag_list = models.CharField(maxlength=150, validator_list=[isTagList],
help_text='Separate tags with spaces. Maximum 250 characters.')
# Details
body_markdown = models.TextField('Entry body', help_text='Use Markdown syntax')
body = models.TextField('Entry body as HTML', blank=True, null=True)
# Dates
last_modified = models.DateTimeField(auto_now = True)
pub_date = models.DateTimeField('Publish Date')
# Misc
enable_comments = models.BooleanField(default=True)
published = models.BooleanField('Publish', default=False)
And I'll just take this opportunity to explain what a slug is, since that has come up quite a few times when people have seen my code. Take, for example, the URL to the first part of this series:
http://kulleen.org/seemant/blog/2007/apr/10/buildi...
The URL to get to the actual blog entry is like this: year/month/day/slug
So the slug is just the Title of the post translated to lower case, with spaces replaced by dashes (my old blog converted them to underscores, you might recall).
Now, there are two body fields, as you can see: body_markdown and body and that is to facilitate typing up the blog (I use markdown syntax for that versus displaying the blog. So in the admin, I type into the body_markdown field, but then the templates only show the body field. That trick is straight out of the Django Cookbook. So that's my blog in a nutshell. If there is enough interest, I'll just make the entire file available, but the magic isn't in that file, it's in some of the supporting code, which we'll get to in the next part.
5 Comments
TEST TEST TEST
test
good example,
please more explanation on : validator_list=[isTagList]
thanks
I'm guessing that the validator_list validates the list that goes into the field to make sure it is a tag list.
Just testing, like the flags