Django is a powerful web framework, created in Python, which follows the DRY (Don’t repeat yourself), and batteries included philosophies. It allows for rapid website development by providing a wide range of tools and shortcuts out of the box. Django is extremely fast and flexible – even faster than all of the PHP frameworks available. In this article, I’ll introduce you to Django by showing you how to build a simple to-do list.
Why Django? Why Not X?
As stated above, Django follows the batteries included philosophy. PHP frameworks such as Code Igniter try and strip all of the “unnecessaries” out for maximum performance; but Django can include all of these out of the box and still be high performance because of its modular design (If you don’t call include feature XX then it isn’t included; so it doesn’t slow the script down). Here are some of the most notable features:
- User/Authentication system
- Automatic RSS generation
- GIS
- Automatically generated Admin interface
- Generic views (more on this later)
- Three level caching system
- Powerful template system
- Comments
MTV
Django runs on an MTV (Model Template View) system (Not the television channel). This is different from MVC.
- Model. The model sets out the schema for our database. Unlike PHP frameworks, you don’t write your queries here. Using Django’s ORM you declare the fields, field types and any additional data such as Meta information.
- View. In the View, you set all of your code logic. You may need to pull some results from the database or manipulate some strings. The view expects a request and a response. The response is typically an http redirect, http error (404), or a call to load a template. When loading a template you usually pass some data through – most likely, results from a database query.
- Template. The template is the plain HTML code with Django’s custom Template ‘language’ (similar to smarty) in it. You look and iterate just like you would with any other language.

Creating Our To-Do List
We are going to create a very simple application, a to-do list, to showcase how to get started with Django. We’ll use the automatically generated admin interface to add, edit and delete items. The ORM will be used to query the database. The view will pull get the to-do items and pass them onto the template where they are shown. I’m going to assume you have Django installed and running.
First, we need to create our project. To do this, we need to use the command line.
django-admin.py startproject todo
That should have created a directory called todo. Go into that directory. (cd todo)
manage.py startapp core
Yours should look similar to the image below.

Now that we have created the project, we need to input some settings. Open up todo/settings.py with your favorite text editor. Django supports a wide range of databases – MySQL, Postgres and Oracle, to name a few. Since we are only developing, we are going to use SQLite. SQLite only requires the name of the database to be specified.
Change Line 12 to:
DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
Change Line 13 to:
DATABASE_NAME = 'to-do.db' # Or path to database file if using sqlite3.
With the database set up. we only need to do a couple more edits in the settings file. On line 69, we need to set a full path to the templates directory where all of our HTML templates will be stored. Create the directory in /todo/core/ and then specify it on line 69. My template directory and installed apps tuple:

Finally, we need to add our application and the admin application into the INSTALLED APPS tuple. So on line 81, insert:
'django.contrib.admin', 'todo.core',
After
'django.contrib.sites',
That’s it for the settings.py file.
Model
Now we need to specify our model. Open /todo/core/models.py with your text editor. As I said above, models define the structure of the database. There’s no need to run raw CREATE TABLE.. SQL queries, Django can do all of this for us. We just need to specify what we want. Since its a to-do list – each to-do will have a title, some content, and the date it was published. It’s very easy to represent this in Django.
from django.db import models class todo(models.Model): #Table name, has to wrap models.Model to get the functionality of Django. name = models.CharField(max_length=100, unique=True) #Like a VARCHAR field description = models.TextField() #Like a TEXT field created = models.DateTimeField() #Like a DATETIME field def __unicode__(self): #Tell it to return as a unicode string (The name of the to-do item) rather than just Object. return self.name
Now that we have defined the database, we need to tell Django to sync all of the tables. We can do this by calling the syncdb command in the command line. Open up the command line and navigate to todo/.
manage.py syncdb
You should get some output for the tables created, as well as a prompt for creating a super user. Create the user and make a note of the username and password, as we’ll use them to login to the admin area. For this tutorial we are going to use Django’s test server to test our application. It is strongly advised that you do not use the test server in deployment, but instead use apache + mod_python or FastCGI. To start the test server, we again call manage.py but with the argument of runserver. We can additionally provide a port for it to run on. By default it runs on port 8000.
manage.py runserver 9090
To view the results we can go to http://127.0.0.1:9090/ .

todo/urls.py
Now we need to set up our URLs. Unlike PHP all URLs in Django are routed. That simply means we specify them ourselves. If a user tries to navigate to a page that isn’t set, it simply returns a 404. Since this is a simple to-do application, we only need to set one URL, the index page. We are also going to enable our admin panel so that we can add, delete and edit our to-do items.
from django.conf.urls.defaults import *
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
(r'^admin/(.*)', admin.site.root), #Lets us access the admin page
(r'^$', 'todo.core.views.index'), #Our index page, it maps to / . Once the page is called it will look in /todo/core/views.py for a function called index
)
The final thing we need to do before we can use the admin panel is to register the model with it. Create todo/core/admin.py and set the contents to:
from django.contrib import admin #Import the admin from models import todo #Import our todo Model. admin.site.register(todo) #Register the model with the admin
Now that the URLs are set, the database is synced, and the model is registered, we can access our administrator panel. Start the test server if it isn’t already and navigate to http://127.0.0.1:9090/admin/ . Login with the super user details you created.

You can see under the core heading there is “todo” – the name of the model. By clicking on this, we can see all of the “to-dos” we have made. The admin interface for making new to-dos is below.

Now that creating, updating and deleting the to-do items are finished, all we need to do is display them. If you navigate to http://127.0.0.1:9090/ you will see an error saying that “the view called index does not exist”. Remember – in the urls.py file, we specified that if the user visited the index, then it would load /todo/core/views.py with the function index()? We’re going to specify that now. We write index() just like any other Python function, except it has to accept a request and return a response.
from models import todo
from django.shortcuts import render_to_response
def index(request): #Define our function, accept a request
items = todo.objects.all() #ORM queries the database for all of the to-do entries.
return render_to_response('index.html', {'items': items}) #Responds with passing the object items (contains info from the DB) to the template index.html
Now all that’s left is to create our template in the todo/core/templates/ directory. In this template, we want to iterate through all of the items (in the object items) and display them on the page. All of the Django logic is wrapped with curly braces; if it’s a variable, then it is wrapped with two curly braces.
<h2>todo</h2>
{% for x in items %}
<p>{{ x.name }} - {{ x.created|date:"D d M Y" }}</p>
<p>{{ x.description }}</p>
<hr />
{% endfor %}
You’re finished! Add a few to-do items in the admin panel, and then go to http://127.0.0.1:9090 . Your layout should look similar to the image below.

Further Reading
I encourage you to learn more about Django if you’re intrigued. Feel free to tweet me with any questions that you might have.


Great Tutorial, I think it will help me get over a few humps, as I try to get going with Google App Engine.
I agree that if you could update the tutorial for Google app engine you would get overwhelmed with traffic,, I’ve been working for days to get to a simple blog example using the Google App engine patch.. Since it combines so many differences none of the tutorial info really works.
There are no tutorials for getting a basic blog engine up and going using Django on Google app engine and only two “examples” as of now, one in Chinese and one which leaves out all the css/js so neither is a great starting point.
@Kevin Quillen
Python is an older and actually much more established than PHP, but in a different area. PHP was designed specifically for the web, while Python is a general language. If you take the time to learn python, (not from Dive Into Python, an awful, awful book) then you’ll notice that it’s extremely easy to use. The syntax is clear and conducive to well written code, and coupled with Django it can significantly improve the time taken to get results out of the door because of the good design principles that Django encourages.
If you use Symfony or other framework for PHP, then fine there’s nothing wrong with that. I like PHP because of it’s resemblance to C/C++ because I originally learnt those languages. But there are some glaring deficiencies which become highlighted when you try to use it for web applications.
Don’t get so defensive about PHP, no one’s saying that PHP is useless. It just has certain weaknesses which make python a more viable language and platform for certain applications.
As for rails, I’m still not entirely convinced. Ruby + Rails is definitely harder to learn than Python and Django because it’s inherently more implicit. There are a _lot_ more conventions which need to be learned in order to use them effectively. My view on RoR however is not authoritative, just my personal experience.
Nice tut. I got most of it working, but couldn’t get the admin interface working right. What version of Django was this written with?
i suggest you work with django 1.3 i tried the above mentioned tut and found it indeed good as well as working completely
I have this error, after adding admin.site.register(todo) #Register the model with the admin
and start the server.
TemplateSyntaxError at /admin/
Caught an exception while rendering: Tried index in module todo.core.views. Error was: ‘module’ object has no attribute ‘index’
Original Traceback (most recent call last):
File “/Library/Python/2.5/site-packages/django/template/debug.py”, line 71, in render_node
result = node.render(context)
File “/Library/Python/2.5/site-packages/django/template/defaulttags.py”, line 370, in render
url = reverse(self.view_name, args=args, kwargs=kwargs, current_app=context.current_app)
File “/Library/Python/2.5/site-packages/django/core/urlresolvers.py”, line 341, in reverse
*args, **kwargs)))
File “/Library/Python/2.5/site-packages/django/core/urlresolvers.py”, line 275, in reverse
possibilities = self.reverse_dict.getlist(lookup_view)
File “/Library/Python/2.5/site-packages/django/core/urlresolvers.py”, line 195, in _get_reverse_dict
self._populate()
File “/Library/Python/2.5/site-packages/django/core/urlresolvers.py”, line 187, in _populate
lookups.appendlist(pattern.callback, (bits, p_pattern))
File “/Library/Python/2.5/site-packages/django/core/urlresolvers.py”, line 137, in _get_callback
raise ViewDoesNotExist, “Tried %s in module %s. Error was: %s” % (func_name, mod_name, str(e))
ViewDoesNotExist: Tried index in module todo.core.views. Error was: ‘module’ object has no attribute ‘index’
Request Method: GET
Request URL: http://localhost:9090/admin/
Exception Type: TemplateSyntaxError
Exception Value:
Caught an exception while rendering: Tried index in module todo.core.views. Error was: ‘module’ object has no attribute ‘index’
——————-
What did I do wrong?
best regards,
magi.
I get this error.
under /core/views.py add:
def index():
pass
i got the same error and tried @ models.py .check the last line of the function _unicode_( self) whether you are returning the correct object or not.If not,you will get the error
Amazing!
This should be the on the django website.
Is exactly what I was looking for! :)))
Thanks.
I was looking for tips on lists – and I didn’t realize I could get something to make my To Do List more than just a bunch of scribbles on a pile of scraps of paper. I need to look more closely at this. Thanks
this website is THE BEST WEBSITE i’ve ever visited,
If you guys have problems, check urls.py
This is my urls.py and mine is working perfectly.
from django.conf.urls.defaults import patterns, include, url
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns(”,
# Examples:
# url(r’^$’, ‘todo.views.home’, name=’home’),
# url(r’^todo/’, include(‘todo.foo.urls’)),
# Uncomment the admin/doc line below to enable admin documentation:
url(r’^admin/doc/’, include(‘django.contrib.admindocs.urls’)),
# Uncomment the next line to enable the admin:
url(r’^admin/’, include(admin.site.urls)),
url(r’^$’, ‘todo.core.views.index’),
)
If you guys have problems, check urls.py
This is my urls.py and mine is working perfectly.
from django.conf.urls.defaults import patterns, include, url
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns(”,
# Examples:
# url(r’^$’, ‘todo.views.home’, name=’home’),
# url(r’^todo/’, include(‘todo.foo.urls’)),
# Uncomment the admin/doc line below to enable admin documentation:
url(r’^admin/doc/’, include(‘django.contrib.admindocs.urls’)),
# Uncomment the next line to enable the admin:
url(r’^admin/’, include(admin.site.urls)),
url(r’^$’, ‘todo.core.views.index’),
)
I don’t quite understand the difference between MTV and MVC. Seems as though in MTV the view is the controller and the template is the view. Or is there a real difference?
What is the name of the file that we are creating inside the /templates folder?
index.html and other html files
Thanks Logan, this tutorial helped me understanding django
Nice tutorial for django beginners
Please more Django tutorial!