Building a Blog with Django

Posted by Ross Poulton on Mon 23 January 2006 #geeky #django

NOTE The Python code in this tutorial no longer works with Django! Please read my new article, a Django Blog Redux, for code that works on newer versions of Django. The rest of this article, such as the theory, is still very much applicable and should be read alongside my newer code.


When I first posted about Django, I said that I'd post the details of how I wrote a blog in Django, without actually writing any real Python code. This will show you how you too can have a simple blog working in no time at all.

I'll assume for this article that you've got Django installed and working, and you know the basics. Create a new project and within it create a 'blog' application. Edit the models file for that application, so it contains the following text:

from django.core import meta

class Tag(meta.Model):
    slug = meta.SlugField(
        'Slug',
        prepopulate_from=("title",),
        help_text='Automatically built from the title.',
        primary_key='True'
    )
    title = meta.CharField('Title', maxlength=30)
    description = meta.TextField(
        'Description',
        help_text='Short summary of this tag'
    )
    def __repr__(self):
        return self.title
    def get_absolute_url(self):
        return "/tag/%s/" % self.slug
    class META:
        admin = meta.Admin(
        list_display = ('slug', 'title',),
        search_fields = ('title', 'description',),
    )
class Post(meta.Model):
    slug = meta.SlugField(
        'Slug',
        prepopulate_from=('title',),
        help_text='Automatically built from the title.',
        primary_key='True'
    )
    assoc_tags = meta.ManyToManyField(Tag)
    title = meta.CharField('Title', maxlength=30)
    date = meta.DateTimeField('Date')
    image = meta.ImageField(
        'Attach Image',
        upload_to='postimgs',
        blank=True
    )
    body = meta.TextField('Body Text')
    def __repr__(self):
        return self.title
    def get_absolute_url(self):
        return "/blog/%s/%s/" % (self.date.strftime("%Y/%b/%d").lower(), self.slug)
    class META:
        admin = meta.Admin(
            list_display = ('slug', 'title', 'date'),
            search_fields = ('title', 'description'),
            date_hierarchy = ('date',),
        )
        ordering = ('-date',)

What this creates for us is three database tables. The first, which will be called 'blog_tags' (a concatenation of the application name, and the pluralisation of the class name) will contain three fields. First is a 'slug', which is an alphanumeric representation of the title (and our primary key). This will be automatically generated from the second field in this table, the title. If the title is, for example, "How To Make A Nice Coffee", the slug will be "how-to-make-nice-coffee" - all in lowercase, with hyphens for spaces, and common short words (such as "a" and "at") removed. Lastly is a description field, which we'll use later in tooltips.

For this tags table, we also define a few functions. The first, repr will return the name of the category by default when ask for a basic view of that category - this makes it easier to use this model later on. We also define a function called 'get_absolute_url' - this is used for us to quickly build a link to view this tag outside of the admin - in this case, we will link to /tag/tag-slug-name/. Later on we will build a template that, when called via this URL, will display a list of articles that belong to that tag. Lastly we define some simple Admin stuff, which I won't detail here.

The second table to be created is called 'blog_posts' and will contain a few simple fields. Again, a slug and title, same as the 'tags' table. It will also contain a ManyToMany field, relating it to the 'tags' table. This lets us select multiple tags for each post, providing a quick and easy way to categorise blog postings without having them tied into only one category. There is also a date field (which, in the Django admin will provide pop-up calendars and time selectors... cool!), an Image field (which lets you attach an image to a post), and a field for the body of the text. Again, we define a repr and basic Admin functions, and a get_absolute_url function: This time the URL will refer to /blog/year/month/day/slug/, which allows each post to have a simple-to-read URL that will never change.

Save your changes, and then edit your 'urls.py' file. Ensure the admin line is uncommented:

(r'^admin/', include('django.contrib.admin.urls.admin')),

Now, visit your /admin/ url, for example http://mydomain.com/admin/. Login with your Django username and password, and you'll see 'Tags' and 'Posts' options in the list. Add a few tags in, noting that the slug is built automatically. Add a few posts, noting you get nice widgets for selecting multiple tags, for picking dates, and building slugfields.

In the next article, find out how we can use Django's generic views to display blog postings, including a date-based archive, by writing practically zero code. Stay tuned, and in the meantime see if you can tweak the above model a little, and learn how objects are represented in the Admin screens.