Throughout the book, we're going to work with the same example site so that we don't have to set up a new project for every chapter. This project will explore all the concepts throughout the book.
Rather than work with the clichéd example of a blog, we'll work with example applications that you'd find in a typical corporate website, such as news and press releases. If you've ever worked a corporate job, you've probably done something like this (and if you haven't, stick it on your resume when you're done!).
The specific configuration directives (project file system locations, database names/passwords, and so on) are given to maintain consistency throughout the book. Feel free to change them to suit your specific needs, but be sure your settings.py
file matches your setup. If you decide to put the project in a different directory on the file system than what is used here, make sure to change your code appropriately when doing the examples in this book. (Hint: It's probably easier to follow along with these values if at all possible!)
Prerequisite #1: Install and test the Django framework
Installing the Django framework is thoroughly covered in the documentation on the DjangoProject.com site. If you have trouble, you can try posting a message to the Django-Users|Google Group (http://groups-beta.google.com/group/django-users).
If you can start a Python shell and successfully run the command import
django
, you should be good to continue.
Note
At the time of this writing, the latest release of Django is 1.0, so that's what we will be using here.
Prerequisite #2: Create a new database
For purposes of this book, it doesn't matter what database engine you use as long as Django supports it (for example, MySQL, PostgreSQL, SQLite, and so on). If you don't have MySQL or PostgreSQL installed, SQLite is probably the easiest choice to work with as it requires zero administration to set up and use.
If you are using MySQL or PostgreSQL, following the instructions of your specific database engine, perform the following tasks. (If you are using SQLite, you don't have to do this.)
Create a database called
mycompany
.Create a user called
mycompany
with a password ofmycompany
.
Step 1: Create the Project Directory
Create a file system location for our Django project files. This is one of the couple of places where your settings might vary depending on the operating system you are using:
For Unix/Mac: Create a /projects/
directory.
For Windows: Create a c:\projects\
directory.
Step 2: Start your project
From the projects directory, run this command:
$ django-admin.py startproject mycompany
This will create a mycompany
directory under projects
.
Note
Note: Rather than writing out both Windows and Mac/Linux versions of the full filesystem path each time we refer to it, the directory will be referred to as mycompany/
instead of /projects/mycompany
or c:\projects\mycompany
. If you see mycompany/
, you can safely assume that we are talking about those directories.
Step 3: Test your installation
In the mycompany
directory, run this command:
$ python manage.py runserver
Browse to http://localhost:8000
and make sure you see the blue It Worked! screen.
During development and testing, you will have to keep starting and stopping the development web server. Anytime you need to browse a URL to test your application, you need to have the server running. Some people like to keep it running in a separate terminal window during development. Just be aware that the web server will restart each time you change a file. If you have a typo in your saved file, the web server may stop and display an error message and you'll need to manually stop and start the web server again when this happens.
Step 4: Configure the project's settings
For the upcoming chapters, we need to make sure Django is configured to use our database. In the mycompany/settings.py
file, edit the database settings to match what you are using:
DATABASE_ENGINE = 'sqlite3' DATABASE_NAME = '/projects/mycompany/mycompany.db' DATABASE_USER = '' DATABASE_PASSWORD = '' DATABASE_HOST = '' DATABASE_PORT = ''
The settings above are valid if you are using SQLite, which is preferable because it requires no configuration. If you are using a different database engine, such PostgreSQL or MySQL, make sure you configure the settings accordingly. Consult the online documentation if you are having trouble.
We now have an empty skeleton of a project upon which we can start building applications. The first application we are going to work with will just be a demonstration to get us warmed up.
Step 1: Create the demo project
In the mycompany
directory, run this command:
$ python manage.py startapp demo
This will create a demo
directory under the mycompany
directory.
Step 2: Add a detail function to the demo view
In the file mycompany/demo/views.py
, add these lines:
from django.http import HttpResponse def detail(request): return HttpResponse('got here!')
Step 3: Add a URL pattern for our demo project
In the file mycompany/urls.py
, edit the file to look like this:
from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^demo/$', 'mycompany.demo.views.detail'), )
This tells the URL dispatcher that if it matches a URL of
http://localhost:8000/demo/
, call the detail function inside the file mycompany/demo/views.py
.
Note
The URL dispatcher automatically strips the http://localhost:8000/
portion when matching, so we don't need to include it as part of our pattern.
Step 4: Make sure it worked
In the mycompany
directory, run this command:
$ python manage.py runserver
This will start the Django development server. You should see something very similar to the following:
Validating models...
0 errors found
Django version 1.0-final-SVN-unknown, using settings 'mycompany.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Browse to http://localhost:8000/demo/
. You should see the got here! line we wrote in our view.
Congratulations! We've created our first Django view. We've built a solid base to start from and we're ready to start playing with views, contexts, and (of course!) templates.
The app we built in the last section serves a page, but it's only a starting point for the application we are going to build. Let's use it to explore some concepts of how Django templates work.
Before we start loading templates, we need to explore the Context
and Template
objects. As we discussed, the context makes variables and objects available to the templates during rendering. We pass it a dictionary of variables and objects and their associated values. When the template is rendered, the placeholders will be replaced with their corresponding values.
Edit your mycompany/demo/views.py
file, adding the highlighted line and replacing your detail
function with this one:
from django.http import HttpResponse
from django.template import Context, Template, loader
def detail(request):
dict_values = {'fav_color': 'blue'}
template_string = "My favorite color is {{ fav_color }}."
c = Context(dict_values)
t = Template(template_string)
rendered_template = t.render(c)
return HttpResponse(rendered_template)
Browse to http://localhost:8000/demo/
and you should see the simple one-liner response:
My favorite color is blue.
So what happened here? Let's break it down.
We created a simple dictionary called dict_values
and populated a key called fav_color
with a value of blue
. If you're not familiar with Python dictionary syntax, check out the code note earlier in this chapter or the Python standard documentation under 'Data Structures'. You'll want to be familiar with this syntax; it's used quite a bit with Django.
We also created a string named template_string
that contains our first taste of the Django template syntax. The double brackets in the string are simply the delimiter used to identify template variables. {{
fav_color
}}
tells the template rendering function that this is a placeholder for the value of the variable fav_color
.
Next, we created a context object named c
and passed it our dictionary. We also created a template object called t
and passed it our template string.
Note
Templates don't have to be stored as files, they can also be strings. When you load a template, Django opens the file and extracts the text into a variable. We're keeping the example simple to start with here and just using a string to represent our template.
When we call the render
method of the Template
object, it parses the template string and replaces any template variables and logic with the appropriate values. In this case, {{
fav_color
}}
was replaced with the value blue
. The rendered template is returned as a string to the rendered_template
variable.
Finally, we send the value of the variable rendered_template
to the browser as an HTTP response. Django nicely handles all the necessary steps of properly formatting the output for the browser to do its work and displaying the HTML.
Keep in mind that the verbosity of this example is intentional to keep the example clear. If you are familiar with Python, you'll know it could be written more concisely like this:
def detail(request): c = Context({'fav_color': 'blue'}) t = Template("My favorite color is {{ fav_color }}.") return HttpResponse(t.render(c))
Templates are usually longer than five words, so let's put the template string into a separate file.
We need to create a templates
directory in our project. Technically, the templates could go anywhere on the file system, but it is common to put them under a templates
directory at the root of your project. Create a directory called templates
under the mycompany
directory.
In your mycompany/settings.py
file, find the TEMPLATE_DIRS
variable (it's actually a Python tuple) and add a reference to our new templates
directory:
TEMPLATE_DIRS = ( '/projects/mycompany/templates/', )
Note
In Windows, use the value c:/projects/mycompany/templates/
. The slashes don't follow the normal Windows syntax, but it's what Django requires.
Even though we are only specifying a single directory of templates, make sure you have the trailing comma after the file path in TEMPLATE_DIRS
. If you omit it, Python will treat your TEMPLATE_DIRS
variable as a string, not a tuple, and you'll get an error when you try to run it.
Note
Adding a trailing comma in a list or tuple is also good practice since Python allows trailing commas. If you always leave a comma after your last item, you won't forget to add it the next time you add another item to the end of the sequence.
While we are in the settings.py
file, let's enable debugging for our project by setting the DEBUG
and TEMPLATE_DEBUG
variables at the top of the file to True
:
DEBUG = True TEMPLATE_DEBUG = True
This will ensure that Django shows us error pages with debugging information instead of a blank page.
Now that we've told Django where to find the templates, let's create a file called example.html
in the mycompany/templates
directory. In the file, add the line that was in our detail
view:
My favorite color is {{ fav_color }}.
We need to change our view to load this new template file. Edit your mycompany/demo/views.py
file and change the detail
view to look like this:
def detail(request): c = Context({ 'fav_color': 'blue' }) t = loader.get_template('example.html') rendered_template = t.render(c) return HttpResponse(rendered_template)
Browse to
http://localhost:8000/demo/
and you should see the same response that we got before we created the template file:
My favorite color is blue
If we want to modify the output of a variable, we can use a template filter. Filters modify the way a context variable is displayed in the output. As we saw earlier, they are applied using a pipe symbol directly after the variable. Do not put a space between the variable and the pipe.
To make the value of our fav_color
variable be displayed entirely in capital letters, we can use the upper
filter. In your mycompany/templates/example.html
file, add the upper
filter to the template fav_color
template variable:
My favorite color is {{ fav_color|upper }}.
Browse to http://localhost:8000/demo/
and you should see this output:
My favorite color is BLUE
We've already seen how variable substitution takes place. So let's use a template tag to perform some simple logic to compare values.
We're going to use the ifequal
tag to test if the fav_color
context variable has the value blue
. The tag uses this syntax: {% fequal <argument1> <argument2> %}
Change your mycompany/templates/example.html
template file to look like this:
{% ifequal fav_color 'blue' %} My favorite color is {{ fav_color }}. {% else %} My favorite color is not blue. {% endifequal %}
Browse to http://localhost:8000/demo/
and you should see this output:
My favorite color is blue.
We can also use template tags to perform looping logic. It is very common in a template to loop over a set of values and perform an action on each value. Let's add a second color to our context variable and use a for
loop in our template to write them out.
First, in your detail
view, change your fav_color
variable to a list of colors by using Python list syntax:
def detail(request): c = Context({ 'fav_color': ['blue','green'] }) t = loader.get_template('example.html') rendered_template = t.render(c) return HttpResponse(rendered_template)
We'll use the for
and endfor
tags to loop through the list of favorite colors. Notice that we are using a variable called color
to hold the value for each iteration of the loop. In this example, fav_color
is our list of colors
from the Context, and color is the current value in the loop. Make sure you change the variable in the curly brackets to use color
.
Replace the contents of your mycompany/templates/example.html
file with these lines:
{% for color in fav_color %} My favorite color is {{ color }}.<br/> {% endfor %}
The resulting output will look like this:
My favorite color is blue.
My favorite color is green.
If you want to add comments to your templates, you have two options: single-line and multi-line comments. If you want to make a comment that only spans a single line, you can wrap your comment with a curly bracket and hash (pound sign) syntax:
{% for color in fav_color %} {# We are writing out a comment here #} My favorite color is {{ color }}.<br/> {% endfor %}
If you want to make comments that span multiple lines, you can wrap your comments in a comment
tag. Note that the comment
tag requires an ending endcomment
tag:
{% comment %} My comment is more than one line long {% endcomment %}