At the Forge - First Steps with Django
When I first began developing Web applications, I did most of my work in Perl, and my programs were invoked via CGI. My preferences have shifted somewhat over the years, first toward component- and template-based systems, such as Mason and Zope, and then toward all-encompassing frameworks, such as OpenACS. Most recently, I've been spending time using Ruby on Rails. As a longtime Perl programmer, I've been pleasantly surprised by both the Ruby language and the Rails framework.
But, of course, Ruby isn't the only popular language out there, and Rails isn't the only popular framework. One of the biggest rivals to Rails during the last year or two has been Django, a Python-based framework with many of the same goals as Rails. Django was first written by Adrian Holovaty while working for a newspaper in Lawrence, Kansas. Holovaty now works for the Washington Post, but he continues to work on the framework along with a host of other open-source contributors.
It would be misleading to say that Django is a Python port of Rails (or vice versa). But, there are many similarities between the two projects. Both Rails and Django grew out of successful commercial projects, the former at 37 Signals and the latter at a newspaper. Both aspire to make Web development fun and easy, removing as much of the drudgery as possible from such work. Both use the model-view-controller (MVC) paradigm for handling actions and creating pages. Both use a particular programming language throughout the system for code and configuration files. And, both have managed to rally a large following, ensuring that they both will continue to be developed for some time to come.
This month, then, I begin a trip into the world of Django to see exactly what it is about this framework that excites people. Even if you're never going to create anything in Django, or you dislike the Python language, I expect there will be something that Django can teach you, or at least make you think about.
The main Web server for Django is at www.djangoproject.com, and you can download a version from there for your own computer. At the time of this writing, the latest official version is 0.96. You can download that version in a .tar.gz file, or you can live on the edge a bit, getting the latest development version via Subversion (svn). I chose the latter path for this column, although if I were working on a commercial site, I might well prefer the stable version.
As is the case with Ruby on Rails, the Django code is not a skeleton Web site, so it should not be placed under a directory that is publicly viewable via the Web. Rather, the code should be installed like any other set of Python libraries and programs on your server, using the standard Python install routine:
python setup.py install
Once this installation is complete, you can use it to create one or more Django projects. The terminology here can be a bit tricky, especially if you're coming from the Rails world, so be careful. A Django project contains one or more applications. Each application then contains sets of models, views and templates. An application can be reused across multiple projects—something like plugins or engines in Rails. For example, you can imagine a calendar application that is used by multiple projects and a portal project that uses several applications (for example, calendar, e-mail and RSS reader) that come from elsewhere.
This means that when we create our Django project, we aren't yet ready to display any code to the world. Rather, we need to create a project and at least one application within that project if we are to see any dynamic output.
Let's create a site (named mysite in the Django tutorials, so I use the same convention here):
django-admin.py startproject mysite
When I installed Django on my Ubuntu box, it placed the administration program django-admin.py in /usr/bin. Your system might have it in a different location, so you might need to modify your PATH to get the above to work as written.
Starting a project in this way creates a directory named mysite, containing four Python source files, each with a .py extension:
A blank __init.py__ file: whenever a directory contains __init.py__, Python sees the entire directory as a single package. So long as the file exists, even if it's blank, our project will be considered a package.
settings.py: this file does not contain executable code, but rather configuration settings for the Django instance. For example, we soon will modify this file to indicate the location and type of relational database that we're using.
urls.py: this is where we will associate URLs to functionality, using regular expressions to match URLs. If you're coming from the Rails world, this is similar in many ways to config/routes.rb.
manage.py: this is a catchall management program for a Django site, handling a large number of administrative tasks, such as starting, stopping and synchronizing the project.
Once again, don't make the mysite directory visible to the world via the Web. Rather, we will expose parts of this directory to the world through our Django project.
If you're coming from the world of Ruby on Rails, this might seem like a very small number of files to begin with. (Out of the box, Rails creates a large number of files and directories.) But, this is because we haven't really created any applications yet, only the package (or container, if you will) that will control and use the application.
The package does have its own HTTP server though, in the same way that Rails comes with one. We can test that things are in order, at least at the package level, by starting up that HTTP server:
python manage.py runserver
This is the first time that we use manage.py, but it is far from the last. The server, which will be running only on the localhost address (127.0.0.1), indicates that the basic framework is up and running and that you now should move ahead with the database definitions.
On the server side, we get the following messages:
Validating models... 0 errors found. Django version 0.97-pre, using settings 'mysite.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
The first two lines indicate that our models—the files with which we describe the contents of our relational database tables—don't exist, which means that they generate 0 errors. (Don't worry; we'll be adding new models, and thus errors, in the near future.) Django also is nice enough to provide version information to indicate the file from which settings are being taken and how we can quit the server.
Part of the reason for using a framework like Django is because it provides us with an excellent object-relational mapper—a fancy way of saying that it turns Python objects into database tables and back without forcing us to work too hard. But, of course, this is possible only if we connect Django to a database.
For this project, I created a small PostgreSQL database named atf:
createdb -U reuven atf
I then can modify settings.py, making the following variable assignments:
DATABASE_ENGINE = 'postgresql' DATABASE_NAME = 'atf' DATABASE_USER = 'reuven' DATABASE_PASSWORD = '' DATABASE_HOST = '' DATABASE_PORT = '5433'
Notice that I had to set DATABASE_PORT to 5433 explicitly. On my system, Django tried to connect to the PostgreSQL server on port 5432, but the database was listening on port 5433.
Before we run the application, we now should synchronize the database. This is the Django term for creating tables that have not yet been defined in the database. We do this by typing (in another shell):
python manage.py syncdb
Now, if you're coming from the Rails world, you might be scratching your head at this point. What tables could Django possibly need to create? I haven't defined any database tables or model objects—what's going on?
The answer is that although Rails and Django are similar in some ways, they differ significantly in other ways. One of those ways has to do with authentication. Django assumes that everyone will want to have an authentication system. After creating the appropriate database tables, Django then prompts you for the user name, e-mail address and password of the superuser for your site. It then finishes with the creation of the administration tables.
Now we can start our server again:
python manage.py runserver
If you are running your Django development site on a machine other than your local workstation, you might want to add an optional IP address and port number:
python manage.py runserver 10.0.0.1:8000
If you point your Web browser at the server you've just set up, you're bound to be disappointed. Yes, we see that Django is running, but we also see that it is giving us an error message when we try to access the server. What's happening?
The simple answer is that we have not yet populated our project with any applications. The project exists, and the server is running, but they are basically an empty shell. Until we create and install one or more applications, we're not going to see very much.
The exception is the Django administrative package, which comes with the system and is immediately available. Well, that's not quite true. It's available, but only if you explicitly modify the list of installed applications (INSTALLED_APPS) to include the appropriate package name. Luckily, we can do that without too much trouble. We open up mysite/settings.py, scroll down to the bottom and modify INSTALLED_APPS such that it includes the string:
You don't even have to restart the server. Once this value has been added, you will be asked to log in with a user name and password. Enter the values that you gave to Django when it created the administrative database, and you'll get a nicely formatted (if sparsely populated) administrative site, complete with links to Django documentation.
Without any other applications installed, it might seem a bit silly to have a Django administrative site. But, one of the things Django provides that Rails doesn't is an underlying authentication and security system. Right out of the box, Django understands that there are users and groups, and that they might need to be assigned different permissions. You easily can add, modify and delete groups, giving them one or more permissions from a provided list.
Even without any applications in place, you can create and administer a system with users, groups and permission levels. It would have been nice if Django were to support hierarchies of groups, rather than the one-level model it currently uses. Regardless, I've always been fond of Web frameworks that come with built-in users, groups and permissions. The fact that Django comes with a graphical system to manipulate them is even better.
This month, we began to look at Django, a popular open-source Web framework written in Python. We got our Django project up and running, including connections to a relational database. We were even able to browse through some of its administrative screens, assigning permissions to users and groups. Next month, we'll continue with our exploration of Django, looking at how we can create new applications with its versions of the MVC (model-view-controller) paradigm.
The main Django site is at www.djangoproject.com. The site contains a great deal of documentation, including tutorials and pointers to mailing lists.
A prerelease copy of the forthcoming Django book (to be published by Apress) is at www.djangobook.com/en/beta, and although the book is still unfinished in many places, it is written well and includes many examples.
If you're interested in comparing Ruby on Rails with Django, there are a number of sites and blog entries that look at them, some with a bit more respect for both sides than others. One thread that I found on the django-users Google group is at groups.google.com/group/django-users/browse_thread/thread/c59a3b4e1fb9cae7?tvc=2.
Reuven M. Lerner, a longtime Web/database consultant, is a PhD candidate in Learning Sciences at Northwestern University in Evanston, Illinois. He currently lives with his wife and three children in Skokie, Illinois. You can read his Weblog at altneuland.lerner.co.il.