Article

Django Djumpstart: Build a To-do List in 30 Minutes

Page: 1 2

Installing the Models

The first step in installing our models is to tell Django which database we're using, and that we want the models we just created to be installed. To do this, open up the settings.py file in your project directory, and change these settings.

DATABASE_ENGINE should be changed to whatever type of database you're going to use. As I mentioned earlier, I'm using MySQL as I write this, so I'll change the setting like so:

DATABASE_ENGINE = "mysql"

DATABASE_NAME should be changed to the name of the actual database you're using:

DATABASE_NAME = "djangotest"

Make sure that this database exists! If you choose to use SQLite, Django can automatically create a database file for you, but that's not possible with MySQL and PostgreSQL.

DATABASE_USER and DATABASE_PASSWORD should be changed to the username and password of a user who has full access to the database. For example:

DATABASE_USER = 'django'  
DATABASE_PASSWORD = 'swordfish'

If you're using SQLite, these settings don't need to be filled in, as SQLite doesn't have a user/password system.

If your MySQL database is hosted on a separate machine, you'll have to set DATABASE_HOST. If MySQL is running on the same server, you can leave this empty.

If MySQL is not set up to listen to its default port, you'll need to set DATABASE_PORT to MySQL's port number.

Down toward the bottom of the settings file is a list called INSTALLED_APPS, which lists all the applications you're using. By default, several of the applications bundled with Django will be listed here. Add gtd.todo to the list like so:

INSTALLED_APPS = (  
 'django.contrib.auth',  
 'django.contrib.contenttypes',  
 'django.contrib.sessions',  
 'django.contrib.sites',  
 'gtd.todo',  
)

Once these settings are changed and saved, type this command in the gtd directory:

manage.py syncdb

You'll see some output scroll past as Django sets up the database tables. It will also prompt you to create a "superuser"; Django's authentication system is installed by default, and creating a superuser account at this point means you'll be able to log in to Django's automatic administrative interface when we set that up. Go ahead and create a superuser now.

Automatic Administration

At this point, we could write our own code to interact with the models we've set up, but Django provides a free, built-in administrative application that lets us start playing with the data immediately. To use it, you only need to do a couple of things:

  • In the settings.py file, add django.contrib.admin to the list INSTALLED_APPS.
  • In the project's urls.py file, locate the line that says "uncomment this for admin", then remove the # from the start of the following line of Python code to uncomment it.

Run manage.py syncdb again, and the administrative interface will be installed.

Now start up the testing server again (by running manage.py runserver) and load http://127.0.0.1:8000/admin/ in your browser, which should show you a login screen. Log in with the username and password you specified for your superuser, and you'll find yourself in Django's admin interface.

1553_admin-home

The main page of the admin system shows a list of installed models, classified by the application of which they're part. If you click on one of the models, you'll see a list of objects for that model. From this page, you can also change existing objects or add new ones.

Let's create a to-do list. On the main admin page, click the "Add" link next to "Lists". Fill in any value you like for the list's title, then save it.

Go back to the main admin page, click the "Add" link next to "Items," and fill in the details for your list's first item. Each item has to be related to a to-do list, and Django will automatically create a drop-down menu that shows all the to-do lists that have been created so far.

1553_admin-edit

This is a pretty nice interface to have -- especially considering how little work was involved in setting it up -- but this is just the default admin interface that Django provides. There are a ton of options (all covered in Django's official documentation) you that can tweak in order to have the admin interface behave the way you want, and you never have to "rebuild" or re-generate any files to use them -- the admin interface is generated on the fly, and changes you make to the configuration can take effect immediately.

If you'd like to learn more about customizing this admin interface, check out the official documentation -- this documentation includes details of how you can enable a very nice edit-in-place feature, which you could use to edit many list items in a single page.

Delving into Views

Now that we have a nice little admin interface, let's talk about views. As nice as the admin interface is, you're probably always going to need at least a couple of additional pages to get your data to appear exactly as you want it to. Views are the functions that generate these pages in your application.

For example, one thing that would be nice to have in this application is a page that shows all of our to-do lists, along with the percentage of items in those lists that have been completed. It would be sort of a "status report" that we could check in on every once in a while. So let's write a view that gives us this status report.

Django views are, for the most part, just ordinary Python functions. The URL configuration file (urls.py) decides which URL goes to which view; Django then calls the correct view function, passing it the incoming HTTP request as an argument. Here's the code for our "status report" view; it should go into the views.py file in the todo directory:

from django.shortcuts import render_to_response  
from gtd.todo.models import List  
 
def status_report(request):  
 todo_listing = []  
 for todo_list in List.objects.all():  
   todo_dict = {}  
   todo_dict['list_object'] = todo_list  
   todo_dict['item_count'] = todo_list.item_set.count()  
   todo_dict['items_complete'] = todo_list.item_set.filter(completed=True).count()  
   todo_dict['percent_complete'] = int(float(todo_dict['items_complete']) / todo_dict['item_count'] * 100)  
   todo_listing.append(todo_dict)  
 return render_to_response('status_report.html', { 'todo_listing': todo_listing })

As Python functions go, this one's pretty simple, but it does show off a few of the nice things that Django can do:

  • List.objects.all, as you might guess, is a method that returns all of our to-do lists so that we can loop through them. Django will figure out the correct SQL and execute it for you automatically.
  • Each to-do list has an item_set property, which represents the list's items. We can use the item_set.all method to get all of the items in the list, or we could use the item_set.filter method to get only a certain subset of the items in the list. We could also use List.objects.filter to get only the to-do lists that match a certain set of criteria.
  • The function render_to_response handles the business of returning an actual web page. It takes the name of a template to use (more on that in a moment), and a dictionary ("dictionary" is Python's name for an associative array) of variables and values to which the template should have access, and takes care of rendering the template and sending an HTTP response.

The actual logic involved here isn't very complex; we're building a list called todo_listing, and each item in it will be a dictionary that contains information about one of the to-do lists. The only really complex part of that is figuring out the percentage of items completed. You'll notice that it does a little bit of typecasting. That's needed because, by default, Python does "integer division" when both of the numbers are integers -- integer division always returns an integer. But we want a decimal number that we can convert into a percentage, so I've explicitly coerced the number of completed items to a floating-point number.

Writing the Template

We've told the view to use a template called status_report.html, but we haven't created that yet. Luckily, creating templates for Django is incredibly easy. In the todo directory, create a new directory called templates, and in it, create the file status_report.html. Here's the code for the template:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml">  
 <head>  
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
   <title>To-do List Status Report</title>  
 </head>  
 <body>  
   <h1>To-do list status report</h1>  
{% for list_dict in todo_listing %}  
   <h2>{{ list_dict.list_object.title }}</h2>  
   <ul>  
     <li>Number of items: {{ list_dict.item_count }}</li>  
     <li>Number completed: {{ list_dict.items_complete }} ({{ list_dict.percent_complete }}%)</li>  
   </ul>  
{% endfor %}  
 </body>  
</html>

For the most part, Django templates look like HTML with just a couple extra things mixed in. There are "template tags," which let you perform some rudimentary logic in the template, and there are variables, which will automatically be filled with values passed in to render_to_response. Tags start with {% and end with %}, while variables start with {{ and end with }}.

In this particular template, we're using two tags: {% for list_dict in todo_listing %} and {% endfor %}. These tags tell the Django template system that we want to loop through each item in this list and do something with it. When we're done with the code in the loop, we use the {% endfor %} tag to say so. Within the loop, we retrieve the values we set in the view in order to display the to-do list's title, the number of items in the list, and so on.

Making it Work

Now that we have our view and template, we just have to give Django a couple pieces of information and it'll all work! First, we need to tell Django where we're storing the templates for our application; this is controlled by the TEMPLATE_DIRS setting in the settings.py file. Just go in and add a line with the path to the location at which you put the "status_report.html" template. In my case, I added this:

'/Users/jbennett/django-projects/gtd/todo/templates',

It's important to put the comma on the end of this line.

Once that's done, we just need to set up a URL for our view, which we do in the urls.py file. Immediately below the line you un-commented earlier for the admin interface's URLs, add this line:

(r'^report/$', 'gtd.todo.views.status_report'),

Again, the comma is important.

Now, start up the testing server (manage.py runserver), and visit http://127.0.0.1:8000/report/. You should see something like this:

1553_report-view

Django's URL configuration is pretty simple; each line in the urls.py file has at least two things in it:

  • a regular expression that specifies the URL or URLs to match
  • the view function to use on URLs matching that regular expression, or a call to include, which can pull in other lists of URLs (the admin interface, for example, has its own urls.py file, and just uses include to tell Django to use that file for any URL that starts with admin)

Where to Go from Here

So far we've written around fifty or sixty lines of code, and we've got the beginnings of a pretty nice little to-do application:

  • We have database tables set up to store the to-do lists and their items.
  • We have a nice administrative interface for creating and managing the lists.
  • We have a quick "status report" page that tells us how we're progressing on each list's items.

That's not bad at all, but it barely scratches the surface of what Django can do; there's a ton of features rolled into Django already, and more are under development. Here are some of the highlights:

  • a full-featured database API
  • a built-in authentication and permissions system for user accounts
  • "Generic views," which save you from having to write code for common things like date-based content archives
  • a built-in cache system to help you squeeze every possible ounce of performance out of Django
  • an internationalization system to make it easy to translate your application's interface into other languages
  • easy, automatic generation of RSS feeds and Google sitemaps
  • easy serialization of data to XML or JSON, for easy use with AJAX
  • plus a whole lot more

If you'd like to learn more about Django, swing by the official site, peruse the documentation (which includes a tutorial that covers a lot of useful pieces of Django), and feel free to ask questions on the Django-users mailing list or in our IRC channel (#django on irc.freenode.net).

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links

Rate This Article

  • 1
    Poor
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
    Great

Comment on This Article

Have something to say?

Post A Comment

You need to be a member of the SitePoint Forums to comment on this post. Sign Up

Already a member? Post using your SitePoint Forums account: