Django Blog Project #4: Adding post metadata

This is my OLD blog. I've copied this post over to my NEW blog at:

You should be redirected in 2 seconds.

I've created a basic blog using SQLite as a backend, deployed it at a shared hosting provider, Webfaction, and added a little CSS for style. Now what? Well, while I say I've created a basic blog, I should say it's a not-quite-yet-basic blog. All it has is some text, which I call Posts, separated by <hr> tags. The next step is to add some post metadata, such as a title, date of creation and tags.

Modify the Post model

To create this new metadata, I first modified the Post model in ~/src/django/myblogsite/myblogapp/

from django.db import models

class Post(models.Model):
    title = models.CharField(maxlength=500)
    date_created = models.DateField()
    tags = models.CharField(maxlength=200)
    body = models.TextField()

    def __str__(self):
        return self.title

    class Meta:
        ordering = ["-id"]

    class Admin:

I added new attributes: title, date_created, and tags. The __str__ method is used to identify a Post instance by its title. This is useful when working in the Administration page. The class Meta: is used to reverse sort the Posts by "id".

Correction 7/6/2008: For the Post's body field, I previously used the line: body = models.CharField(maxlength=999999). However, thanks to Myles's comment below, I've changed this to use the more appropriate TextField.

python syncdb

Whoops, running python syncdb doesn't actually sync the model with the database. It is only used to initially create the database tables. To add the new columns to my table, I would have to enter the SQL commands directly. Though it is not super difficult, and would be good experience since all those hiring managers seem to want SQL experience, I took the lazy route and just replaced my database. (Not like I had much in there anyways.) For your reference, the section Making Changes to a Database Schema in Chapter 5 of The Django Book describes how to solve my problem without replacing my database.

$ cd ~/src/django/myblogsite
$ rm mydatabase.sqlite3 
$ python syncdb 
Creating table auth_message
Creating table auth_group
Creating table auth_user
Creating table auth_permission
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table django_admin_log
Creating table myblogapp_post

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (Leave blank to use sofeng'): sofeng
E-mail address: my@email.address
Password (again): 
Superuser created successfully.
Installing index for auth.Message model
Installing index for auth.Permission model
Installing index for admin.LogEntry model
Loading 'initial_data' fixtures...
No fixtures found.

Oh yeah, I forgot gotta recreate my superuser.

Modify slightly

In versions 0.0.1 and 0.0.2 of my new blog, I passed a list of post bodies to my template. But actually, I could have just passed a list of the Post objects and accessed the body attribute of each post in the template. This saves a line of unecessary code, and provides accessiblity to all the attributes of the Post object. (I also factored out my blog version number from the base.html template.)

from django.shortcuts import render_to_response
from myblogsite.myblogapp.models import Post

def frontpage(request):
    posts = Post.objects.all()
    return render_to_response('frontpage.html', 
                              {'post_list': posts,
                               'VERSION': '0.0.3'})
Correction 7/6/2008: I previously had from myblogapp.models import Post on the second line. This works, but is inconsistent with my below and can (and did for me) cause subtle errors in the future. I corrected the line to read: from myblogsite.myblogapp.models import Post.

Modify my frontpage.html template

This is pretty self-explanatory. I access the the Post object's attributes using the "." (dot).

{% extends "base.html" %}

{% block main %}
  {% for post in post_list %}
    <h2>{{ post.title }}</h2>
    {{ post.body }}
    <div class="post_footer">Created: {{ post.date_created }} | Tags: {{ post.tags }}</div>
  {% endfor %}
{% endblock %}

A little CSS

In between the <style> tags in ~/src/django/myblogsite/templates/base.html:

.post_footer {
  font-family: Verdana, Arial, sans-serif;
hr {
  border: 0;
  color: gray;
  background-color: gray;
  height: 1px;

Start development server and add a couple posts

I started the development server and added a couple of posts in the Admin site:

  • $ cd ~/src/django/myblogsite
    $ python runserver
  • I visited, logged in, and added a couple posts.

Upload to Webfaction server

pushwebf is my alias for hg push --remotecmd /home/sofeng/bin/hg ssh://

$ pushwebf's password:
pushing to ssh://
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 7 changesets with 20 changes to 10 files

Logged into Webfaction:
$ cd ~/webapps/django/myblogsite
$ hg update -C
9 files updated, 0 files merged, 4 files removed, 0 files unresolved
$ ~/webapps/django/apache2/bin/restart

Here is a snapshot screenshot of version 0.0.3

The live site can be viewed at

Related posts:
   Django Blog Project #1: Creating a basic blog
   Django Blog Project #2: Deploying at Webfaction
   Django Blog Project #3: Using CSS and Template Inheritance
   Django Blog Project #5: YUI CSS and serving static media


Myles said...

Why use: models.CharField(maxlength=999999) when you could use models.TextField().

sofeng said...

Myles, Because I didn't know about models.TextField()! Thanks for the tip!


This is my *OLD* blog. I've copied all of my posts and comments over to my NEW blog at:

Please go there for my updated posts. I will leave this blog up for a short time, but eventually plan to delete it. Thanks for reading.