File Under: Frameworks, Programming

Install Django and Build Your First App

In our Introduction to Django, we covered all the basics of using the open source web-building framework. If you haven’t read through our beginner’s tutorial, go ahead and do so now. If you’ve already made it through the easy stuff, you’re probably ready to dive into some code and start building — so let’s do it.

Our first step is to grab a copy of Django and set up a development environment where we can tinker away.

Contents

  1. Install Django
  2. Set up your first project
  3. Fill out the project settings
  4. Set up a user
  5. Start the server
  6. Build the blog
  7. Check your head
  8. Tweak the links and tags
  9. Onward and upward

Install Django

Django 1.1 was released on July 29th, 2009. You can download the official release here and follow these instructions for installing.

Alternatively, if you want to get the latest and greatest Django tools, you can checkout a copy of the trunk build using Subversion.

If you don’t have Subversion installed, go grab a copy.

Then fire up your terminal and paste in this line:

 svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk

Once all the files finish downloading, we need to make sure our local Python installation is aware that Django exists on our machine. There are a couple ways to go about that, but a symbolic link to your Python site packages directory is probably the easiest.

Assuming you’re on a *nix system, this line will do the trick:

ln -s `pwd`/django-trunk/django /path/to/python_site_packages/django

If you don’t know where your Python site directory is, here’s a handy bit of Python that will tell you:

python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

If you’re on Windows, the easiest thing to do is add Django to your PythonPath environment variable. On Windows, you can define environment variables in the Control Panel. To do this, see Microsoft’s Command Line Reference for more details.

The excellent and well-written Django installation docs suggest creating a symbolic link to the file django-trunk/django/bin/django-admin.py in a directory on your system path, such as /usr/local/bin. I find that I don’t use django-admin.py all that often, but you can create the link if you like.

Just paste this code in your shell:

ln -s `pwd`/path/to/django-trunk/django/bin/django-admin.py /usr/local/bin

Now that Django is installed and Python knows where it lives, we’re ready to get started.

Remember that you have a Subversion checkout now. If you ever want to update to the latest release, just head to the “django-trunk” folder and run svn update.

Set up your first project

OK, let’s get started. From the command line, switch to your web development directory. Something like this:

cd ~/sites/dev

Now we’re going to run the django-admin tool we mentioned earlier. If you created the symlink, you don’t need the full path, but if you didn’t here’s the code:

python /path/to/django-trunk/django/bin/django-admin.py startproject djangoblog



Yep, you read that last bit correctly — we’re going to build a blog.

Now cd over to the new folder:

cd ~/sites/dev/djangoblog

This is going to be our project folder into which we will add various apps. Some we’ll create and some we’ll be downloading as projects from Google Code. I like to keep my Python import statements clean and free of project-specific module names, so I always make sure my root project folder (in this case, djangoblog) is on my Python path. To do that, just add the path to your PythonPath variable.

That way we can write statements like:

import myapp

rather than

import myproject.myapp



It’s not a huge thing, but it does make your code more portable.

Fill out the project settings

OK, we’re getting there. The next step is to fill out our project settings file. Fire up your favorite text editor and open up the settings.py file inside the “djangoblog” directory.

The core of what we need to set up is at the top of the file. Look for these lines:

DATABASE_ENGINE = 'sqlite3'  # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.

DATABASE_NAME = '/path/to/djangoblog/djangoblog.db' # Or path to database file if using sqlite3.

DATABASE_USER = ''             # Not used with sqlite3.

DATABASE_PASSWORD = ''         # Not used with sqlite3.

DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.

DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.

Note that we’re using SQLite as a database for development purposes. Assuming you have Python 2.5 installed, you don’t need to do anything to use SQLite. If you’re on either Python 2.3 or Python 2.4, you’ll need pysqlite — make sure you install version 2.0.3 or higher. If you have MySQL or PostgreSQL already installed, feel free to use them.

Make Sure to include the entire pathname, as Django cannot understand ~/ or $HOME in defining the database ie /Users/usrname/Sites/dev/djangoblog/djangoblog.db

The other settings are well documented in the settings.py file and we can skip over most of them for now. But there are a couple of settings we should take care of before moving on. If you look at the bottom of the settings.py file you’ll notice this bit of code:

INSTALLED_APPS = (

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.sites',

)

This where we tell our Django project which apps we want to install. In a minute, we’ll add our blog app. But for now let’s just add Django’s built-in admin tool. Paste in this line just below the sites app:

'django.contrib.admin',

One more thing before we finish with settings.py, here’s a handy trick for the template directories. I generally keep all my templates in a folder named “templates” within my project folder (in this case, “djangoblog”). But I generally move between development and live servers quite a bit and I hate having to change the path to the templates folder. This trick takes care of that:

import os.path

TEMPLATE_DIRS = (

	os.path.join(os.path.dirname(__file__), 'templates'),

)

Instead of hard coding the path to our templates folder this is dynamic — and it showcases how easy it is to tweak Django using Python. We just import the os.path Python module and then find the path to the directory where settings.py is and then appends ‘templates’ to that path.

Now when we push the site live, there’s no need to change the settings.py file. (Actually you’d probably want to switch to a more robust database, but we’ll get to that much later).

For now, let’s use one of the tools included in manage.py, the syncdb tool. Paste this line in your terminal:

python manage.py syncdb

The syncdb tool tells Django to translate all our installed apps’ models.py files into actual database table. In this case the only thing we have installed are some of the built-in Django tools, but fear not, we’ll get to writing our own models in just a minute.


Set up a user

Once you enter the syncdb line above, you’ll get some feedback from Django telling you you’ve just installed the auth system. It will walk you through setting up a user. The output looks like this:

sng: /djangoblog/ $ python manage.py 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



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 'luxagraf'):

E-mail address: none@none.com

Password:

Password (again):

Superuser created successfully.

Installing index for auth.Message model

Installing index for auth.Permission model

Installing index for admin.LogEntry model

sng: /djangoblog/ $

Once you’ve created your username and password, it’s time to fire up Django’s built-in server.

Start the server

At the command prompt, tell Django to start the server:

/djangoblog/ $ python manage.py runserver

Validating models...

0 errors found



Django version 0.97-pre-SVN-6920, using settings 'djangoblog.settings'

Development server is running at http://127.0.0.1:8000/

Quit the server with CONTROL-C.

Now open up your browser and head to http://127.0.0.1:8000/. You should see a page like this:

Image:Djangopart2_1.jpg

It works! But that isn’t very exciting yet, so let’s check out the admin interface. However, before we do that, we need to tell Django what the admin URL is.

Fire up your text editor and open the file urls.py in your “djangoblog” folder. Copy and paste the code below, replacing what’s already in the file:

from django.conf.urls.defaults import *

from django.contrib import admin



# Uncomment the next two lines to enable the admin:

# from django.contrib import admin

admin.autodiscover()



urlpatterns = patterns('',

     (r'^admin/(.*)', admin.site.root),

)



Now head to http://127.0.0.1:8000/admin/. Log in with the user/pass combo you created earlier and you should see something like this:

Image:Djangopart2_2.jpg

Now that’s pretty cool. If you’ve ever labored over creating an admin system in Ruby on Rails or PHP, you’re going to love Django’s built-in admin system.

But at the moment there isn’t much to see in the admin system, so let’s get started building our blog.

Build the blog

Now we could just throw in some code that creates a date field, title, entry and other basics, but that wouldn’t be a very complete blog would it? What about tags? An RSS feed? A sitemap? Maybe some Markdown support for easier publishing?

Yeah, let’s add all that. But remember Django’s DRY principles — surely, somebody else has already created a Feed app? A Sitemap app?

As a matter of fact Django ships with those built-in.

Nice. But what about tags? Well there’s one of those apps available as well — the cleverly named django-tagging.

Now, there have been some backwards-incompatible changes to Django recently, and as of this writing, django-tagging hasn’t caught up to those yet. So we’re actually going to need to checkout the Newforms Admin branch of the django-tagging codebase.

To do that we’ll grab the files using Subversion. Paste this code into your terminal window:

svn checkout http://django-tagging.googlecode.com/svn/branches/newforms-admin django-tagging

Now cd into the new django-tagging folder and type:

python setup.py install



Then just drop the tagging folder, which you’ll find inside django-tagging, in your “djangoblog” folder or wherever you’d like to keep it (I use a “lib” folder to hold all my frequently used components, like django-tagging).

There’s also a handy Python implementation of Markdown, so grab that as well (follow the setup instructions on the site to get Markdown installed). Markdown is entirely optional, so feel free to skip it if it’s not your thing.

Got all that stuff stashed in your “djangoblog” folder? Good.

Now let’s go ahead and create our first Django application.

To do that we’ll use Django’s app creating script, which lives inside manage.py in our project folder. Paste this line into your shell:

python manage.py startapp blog

If you look inside “djangoblog” you should now see a new “blog” folder. Open that up and find the models.py file. Open models.py in your favorite text editor and paste in this code:

from django.db import models

from django.contrib.syndication.feeds import Feed

from django.contrib.sitemaps import Sitemap



import markdown

from tagging.fields import TagField

from tagging.models import Tag



# Create your models here.



class Entry(models.Model):

    title = models.CharField(max_length=200)

    slug = models.SlugField(

        unique_for_date='pub_date',

        help_text='Automatically built from the title.'

    )

    body_html = models.TextField(blank=True)

    body_markdown = models.TextField() #note, if you're using Markdown, include this field, otherwise just go with body_html

    pub_date = models.DateTimeField('Date published')

    tags = TagField()

    enable_comments = models.BooleanField(default=True)

    PUB_STATUS = (

        (0, 'Draft'),

        (1, 'Published'),

    )

    status = models.IntegerField(choices=PUB_STATUS, default=0)



    class Meta:

        ordering = ('-pub_date',)

        get_latest_by = 'pub_date'

        verbose_name_plural = 'entries'



    def __unicode__(self):

        return u'%s' %(self.title)



    def get_absolute_url(self):

        return "/%s/%s/" %(self.pub_date.strftime("%Y/%b/%d").lower(), self.slug)



    def save(self):

         self.body_html = markdown.markdown(self.body_markdown, safe_mode = False)

         super(Entry, self).save()


Let’s step through the code line by line and we’ll talk about what’s going on.

First we import the basic stuff from django, including the model class, the Feed class and the Sitemap class.

Then we import the tagging and markdown files we just saved in our project folder.

Once we have all the modules we’re going to use, we can create our blog model. I elected to call it Entry — you can change that name if you like, but remember to substitute your name everywhere I refer to Entry.

Entry extends Django’s built-in model.Model class, which handles all the basic create read update and delete (CRUD) tasks. In other words, all we have to do is tell Django about the various elements of the database table (like the title field, the entry slug, et cetera) and all the hard work is handled behind the scenes.

The first bit of our Entry class definition just defines all our various blog entry components. Django will use this information to create our database tables and structure, and also to generate the Admin interface.

Note that we’re using Django’s various model fields. Most of it should be self-explanatory, but if you want to learn more about each type, check out the Django documentation. Also be aware that there are quite a few more field types available. This is only one example.

One thing worth mentioning is the body_html = models.TextField(blank=True) line. What’s up with that blank=True bit? Well that information is part of Django’s built-in Admin error checking.

Unless you tell it otherwise, all fields in your model will create NOT NULL columns in your database. To allow for null columns, we would just add null=True. But adding null=True only affects the database, Django’s Admin system would still complain that it needs the information. To get around that, we simply add the blank=True.

In this case, what we’re going to do is fill in the body_html field programatically — after we hit save in the Admin and before Django actually writes to the database. So, we need the Admin section to allow body_html to be blank, but not null.

Also worth mentioning is the Meta class. Meta handles things like how Django should order our entries and what the name of the class would be. By default, Django would refer to our class as “Entrys.” That offends my grammatical senses, so we’ll just explicitly tell Django the proper plural name of “entries.”

Next, we have a few function definitions. All Python objects should return their name. Django recently added unicode support, so we’ll return our name in unicode. Then there’s get_absolute_url. As you might imagine this refers to the entry’s permalink page.

When we get to creating templates, we’ll use this to put in our permalinks. That way if you ever decide to change your permalinks you only have to change one line and your entire site will update accordingly — very slick.

The last function simply overrides Django’s save function. Every Django model has a save function, and since we didn’t expose the body_html field, we need to fill it in. So we grab the text from our body_markdown field (which is exposed in the admin), run it through the markdown filter and store it in body_html.

By doing it this way, we can just call this field in our templates and we’ll get nicely formatted HTML as output, yet the process stays transparent — write in markdown, display HTML.

If you’re not using Markdown, just delete the save function, there’s no need to override it if you aren’t using the Markdown module.


Check your head

Now we need to tell Django about our new apps. Open up settings.py again and add these lines to your list of installed apps:

INSTALLED_APPS = (

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.sites',

    'django.contrib.admin',

    'djangoblog.tagging',

    'djangoblog.blog',

)


Once that’s done, head over to the terminal and run manage.py syncdb. Refresh your admin section and you should see the tagging application we downloaded. Super cool.

But where’s our blog model? Well, even though Django knows about our blog app, we haven’t told the app what to do in the Admin section.

So head back over to your text editor and create a new file. Name it admin.py and save it inside the “blog” folder. Now add these lines:


from django.contrib import admin



from djangoblog.blog.models import Entry



class EntryAdmin(admin.ModelAdmin):

    list_display = ('title', 'pub_date','enable_comments', 'status')

    search_fields = ['title', 'body_markdown']

    list_filter = ('pub_date', 'enable_comments', 'status')

    prepopulated_fields = {"slug" : ('title',)}

    fieldsets = (

		(None, {'fields': (('title', 'status'), 'body_markdown', ('pub_date', 'enable_comments'), 'tags', 'slug')}),

    )



admin.site.register(Entry, EntryAdmin)

OK, what does all that do?

The first thing we do is import Django’s admin class, as you might suspect, admin controls how the admin interface looks. Now, these customizations are entirely optional. You could simply write pass and go with the default admin layout. However I’ve customized a few things and added some filters to the admin list view so we can sort and filter our entries. Note that if you aren’t using Markdown, just replace body_markdown with body_html.

We’ve also used a handy tool, Django’s prepopulated_fields, which will use a bit of Javascript to automatically build a slug from our title.

The last step is to register our admin customizations with Django’s admin app. If you aren’t actually making any customizations, you could just write the model name. In other words the admin class name is optional.

If you refresh your admin page you should now see the blog model with a link to create and edit blog entries.

Want more control over what shows up in your admin? For instance, if it’s a personal site, you probably don’t need the “Users” section in the admin. Let’s customize what shows up. To do that we’re going to create a new file, again named admin.py, but put this one at the project level, inside the djangoblog folder.

Okay now paste in this code:

from django.contrib import admin

from djangoblog.blog.models import Entry

from djangoblog.blog.admin import EntryAdmin



class AdminSite(admin.AdminSite):

    pass







site = AdminSite()

site.register(Entry, EntryAdmin)

All this does is override Django’s default AdminSite and then simply registers our Entry model and admin classes. Of course you could do more than simply pass, check the Django docs for customization tips.

Now if you go back and refresh the admin page you should see just the things we’ve built — the Entries and Tags models.

Tweak the links and tags

One last thing, let’s jump back over to our models.py file; we’re going to add one extra function to our blog to improve its usability. Add these lines to the bottom of your models.py file:

    def get_previous_published(self):

        return self.get_previous_by_pub_date(status__exact=1)



    def get_next_published(self):

        return self.get_next_by_pub_date(status__exact=1)



    def get_tags(self):

        return Tag.objects.get_for_object(self)



So what’s going on here?

Django includes a bunch of built-in methods for common tasks, like displaying next and previous links on pages. The function is called get_previous_by_ with the last bit of the function being the name of your datetime field, in our case pub_date. However, we included the ability to save drafts in our model, and, unfortunately, Django’s built-in function doesn’t know about our drafts. So, it will automatically include them in our next/previous links. This obviously isn’t what we want.

So what we’ve done is wrap the Django function with a one-liner:

    def get_previous_published(self):

        return self.get_previous_by_pub_date(status__exact=1)

All this does is wrap the Django function with a new name get_next_published, call the original get_previous_by_ function, but add a filter so that only published entries are included in the results.

The last function in that set, get_tags, is just a time saver. There’s a good chance you’ll want to list all the tags you’ve added to your entry, so I’ve included a convenience method that does just that.

Onward and upward

Whew! That’s a lot of code to sort through, and we’ve glossed over a few things. But when you look at the models.py file and consider that from these 49 lines of code, Django was able to generate an entire blog website, it doesn’t seem like so much code at all, does it?

Save the file and head back over to your browser. Refresh the admin page and click “Add new.” Feel free to create a few entries — blog monkey blog!

So now we’ve got our back-end blogging system set up and everything in in place to create a public site. Feel free to take a well deserved break.

The next thing to do is dress up the public-facing side of our blog, which is functional, yet totally vanilla. We tackle that in Lesson 3: Use URL Patterns and Views in Django, so click ahead once you feel ready.

In the meantime, you’ve learned enough about Django to continue building the backend, and you can always consult the Django Book if you want to strike out on your own.

Good luck!