C H A P T E R   2

image

Your First Django Site: A Simple CMS

One extremely common task in web development is building a simple content management system (CMS), which lets users dynamically create and edit pages on a site through a web-based interface. Sometimes called brochureware sites because they tend to be used in the same fashion as traditional printed brochures handed out by businesses, they're usually fairly simple feature-wise, but can be tedious to code over and over again.

In this chapter, you'll see how Django makes this kind of site almost trivially easy to build. I'll walk you through the setup of a simple CMS, and then in the next chapter you'll see how to add a few extra features and provide room to expand it in the future.

Configuring Your First Django Project

In the last chapter, you created a Django project called cms. But before you can do much with it, you'll need to do some basic configuration. So launch your favorite code-editing program and use it to open the settings.py file in your project.

Don't be daunted by the size of the settings.py file or the number of settings you'll find in it. django-admin.py automatically filled in default values for a lot of them, and for now most of the defaults will be fine. Near the top of the file is a group of settings whose names all start with DATABASE_. These settings tell Django what type of database to use and how to connect to it, and right now that's all you need to fill in.

If you installed the latest version of Python, you'll already have a database-adapter module that can talk to SQLite databases (Python 2.5 and later include this module in the standard Python library). SQLite is a great system to use when you're starting to explore Django because it stores the entire database in a single file on your computer, and it doesn't require any of the complex server or permissions setup of other database systems.

To use SQLite, you need to change only two settings. First, find the DATABASE_ENGINE setting and change it from this:

DATABASE_ENGINE = ''

to this:

DATABASE_ENGINE = 'sqlite3'

Now you need to tell Django where to find the SQLite database file; this information goes into the DATABASE_NAME setting. You can put the file anywhere on your computer's hard drive where you have permission to read and write files. You can even fill in a nonexistent file name, and the SQLite database engine will create the file for you automatically. Keeping the database file inside your project folder isn't a bad idea in this case, so go ahead and do that. I keep all of my Django projects in a folder called django-projects inside my home directory (on a laptop running Mac OS X), so I'll fill it in like this:

DATABASE_NAME = '/Users/jbennett/django-projects/cms/cms.db'

This path will look a bit different on other operating systems, of course. On Windows it might be C:Documents and Settingsjbennettdjango-projectscmscms.db, for example, while on a Linux system it might be /home/jbennett/django-projects/cms/cms.db.

I'm telling Django that the SQLite database file should live inside the cms project directory with a file name of cms.db. The .db file extension isn't required, but it helps me remember what that file is for, so I recommend you use a similar naming convention.

Finally, you'll probably want to change the TIME_ZONE setting, which tells Django which time zone to use when displaying dates and times from your database. Your database typically stores dates and times as Universal Time, Coordinated (UTC) timestamps (UTC is the “base” time zone formerly known as Greenwich Mean Time, or GMT). Rather than use a country-specific time-zone name (like U.S. Central Standard Time) or a confusing UTC offset (like UTC-6), the TIME_ZONE setting uses names in zoneinfo format. This standard format, used by many computer operating systems, is easy for humans to read. The default setting is

TIME_ZONE = "America/Chicago"

which is equivalent to the U.S. Central time zone, six hours behind UTC. Full lists of zoneinfo time-zone names are available online, and the official Django settings documentation at www.djangoproject.com/documentation/settings/ includes a link to one such list. You should change your TIME_ZONE setting to the zone in which you live.

You won't need to change it yet, but locate a setting called INSTALLED_APPS by scrolling down to the bottom of the settings file. As mentioned previously, a Django project is made up of one or more Django-powered applications, and this setting tells Django which applications your project is using. The default value looks like this:

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

Each of these is an application bundled with Django itself, and each provides a useful piece of common functionality. django.contrib.auth, for example, provides a mechanism for storing data about users and for authenticating them. django.contrib.sites lets you run multiple web sites from a single Django project and specify which items in your database should be accessible to each site.

In time, you'll see examples of these applications in action, but for now it's best to leave the defaults as they are. They provide a “quick start” to your project by taking care of many tasks right away, and you'll soon build on their functionality.

Now that you've given Django some basic configuration data, you can tell it to set up your database. Open a terminal or command prompt, navigate to your project's directory, and type this command:

python manage.py syncdb

This command will create the database file if needed and then create the database tables for each application listed in the INSTALLED_APPS setting. First you'll see several lines of output scroll by. Then, because the bundled user-authentication application is being installed, Django will ask if you'd like to create a “superuser” account for web-based administration. Type yes, and then enter a username, e-mail address, and password when prompted. You'll see shortly how you can use this account to log in to a Django administrative interface.

Putting Together the CMS

Most of the applications you'll build with Django will require you to write a fair amount of code on your own. Django will take care of the heavy lifting and the repetitive tasks, but it'll still be up to you to handle features unique to each specific application. Sometimes, though, features built into Django or applications bundled with it will provide most or all of what you need. The contrib applications bundled with Django, for example, provide functionality you'll likely reuse from project to project.

You'll build your simple brochureware CMS by relying heavily on two of Django's contrib applications: django.contrib.flatpages and django.contrib.admin.

The first of these, django.contrib.flatpages, provides a data model for a simple page, including a title, content, and a few configurable options such as custom templates or authentication. The other application, django.contrib.admin, provides a powerful administrative interface that can work with any Django data model, letting you create a more or less “instant” web-based interface to administer a site.

The first step here is to add these applications to the INSTALLED_APPS setting. Remember that Django placed four applications in the list by default. Now you can add two more:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    'django.contrib.flatpages',
)

Once you've made that change and saved your settings file, run syncdb again:

python manage.py syncdb

You'll see the output scroll by as Django creates database tables for the data models defined in these applications. Now open your project's urls.py file, which—as you saw in the previous chapter—contains the root URL configuration for your project. To enable the administrative application, follow the instructions to “uncomment” lines in two places in this file: two lines near the top of the file containing import statements and one line near the bottom, which I'll cover shortly.

imageNote Python comments are lines that begin with the character “#” and that don't execute as code. They either provide information to a person reading the file or point to code that has been temporarily disabled. (The author might have disabled the code because some feature needed to be turned off momentarily or because a bug needed to be tracked down.)

In each of these places in urls.py, uncomment the lines of code by removing the comment marker at the beginning of the line and the space following it. (Removing the space is important, because Python interprets spaces as indicating the structure of the code.) Then save the file. Now your project's urls.py file imports the necessary code from the admin application and includes the necessary URLs to make it work.

Now you'll be able to launch the built-in web server again and see the administrative interface:

python manage.py runserver

The URL pattern for the admin application is ^admin/, which means that if you visit http://127.0.0.1:8000/admin/ in your web browser, you'll see the login page. Enter the username and password you used when syncdb prompted you to create a user account, and you'll see the main admin index page (see Figure 2-1). But note that URLs beginning with admin/ are the only ones that will work right now; you haven't set up any other URLs yet.

image

Figure 2-1. Home page of the Django administrative interface

Each item listed on the index page corresponds to a data model in one of the installed applications. The items are grouped according to which application they belong to. The auth application, django.contrib.auth, provides models for users and groups; the sites application, django.contrib.sites, provides a model to represent a web site; and the flatpages application you just installed provides a “flat-page” model. To the right of this list is a Recent Actions sidebar, which reports actions you've taken recently in the admin interface. It's empty now because you haven't done anything yet, but it will show a summary of your actions as soon as you start making changes to site content. As a first step, click the Sites link. You'll see a screen like the one shown in Figure 2-2.

As part of its initialization, django.contrib.sites created an example site “object” for you, which you can click to edit. Because the built-in web server is running on your computer's local loopback interface at port 8000, change the Domain Name field to 127.0.0.1:8000 and change the Display Name field to localhost. Then click the Save button at the bottom-right corner to save your changes to the database. If you go back to the main index of the admin interface, you'll see that the Recent Actions sidebar now has an entry for that site, showing that you've changed it recently.

image

Figure 2-2. The default site object created by Django

You'll notice that the main admin page displays an Add link and a Change link next to each type of item (see Figure 2-1). Add a new flat page by clicking the Add link next to the Flat Pages link. This will bring up a blank form, automatically generated from the appropriate data model. Enter the following values:

  • In the URL field, enter /first-page/.
  • In the Title field, enter My first page.
  • In the Content field, enter This is my first Django flat page.

Then scroll down and click the Save and Continue Editing button. Django will save the new flat page into your database and then redisplay the form so you can edit the page. You'll also notice that two buttons have appeared above the form: History and View on Site. The History button shows a simplified history of this flat page (right now, nothing but the initial entry for it has been created). The View on Site button lets you see the flat page at its public URL. Clicking the View on Site button redirects you to http://127.0.0.1:8000/first-page/, which will, for the moment, display an error message like the one shown in Figure 2-3.

image

Figure 2-3. A Django “Page not found” error

This is a 404 “Page not found” error, but with a twist—every new Django project starts out in debugging mode, which displays more useful error messages to help you get up and running. In this case, Django shows you the URL patterns it found in your project's URLConf, and explains that the URL you tried to visit didn't match any of them. This makes sense because you haven't yet added anything that looks like the URL /first-page/. So let's fix that. Open the urls.py file again and add the following line right below the URL pattern for the admin interface:

(r'', include('django.contrib.flatpages.urls')),

The pattern part of this is simply an empty string (‘’), which in regular-expression syntax means it will actually match any URL. If you wanted to, you could go into urls.py and add a new line each time you add a flat page. You'll mostly define individual URLs in applications you'll develop later, but because django.contrib.flatpages lets you specify anything for a page's URL, it's easiest in this case to simply place a “catch-all” URL pattern to handle it.

The URL pattern for the admin simply specified admin.site.root to handle any incoming HTTP request for a URL matching its regular expression. (admin.site.root is a Django view, which responds to an HTTP request.) But this new pattern for flat pages uses include, a function that tells Django instead to use a different URLConf module (django.contrib.flatpages.urls) for requests that match its regular expression. Using include like this allows you to quickly “plug in” different sets of URLs when and where you need them.

Also, notice that instead of specifying the URLConf through its location on disk (such as django/contrib/flatpages/urls.py), the syntax specifies it by using the same style that you use when importing Python code: module and submodule names separated by dots. This is a common pattern in Python because there are functions that can dynamically carry out the same tasks as the import statement. You'll find the pattern extremely useful.

Save your urls.py file and either refresh the page in your browser or navigate again to http://127.0.0.1:8000/first-page/. The page still displays an error, but now you're closer to having the simple CMS working (see Figure 2-4).

image

Figure 2-4. A Django server error page

This page looks a little scary, but it's actually not. Once again, Django's debugging mode tries to give you as much information as it can. The top of the page shows a short summary of the error, followed by more detailed information, including a full stack trace (a copy of everything Python and Django were doing when the error happened), a listing of the incoming HTTP request, and your Django project's settings (with any sensitive settings, such as database passwords, blanked out for security reasons).

The problem here is that a flat page, like most output from Django, expects to be displayed via a template that generates the correct HTML. django.contrib.flatpages, by default, looks for a template file named flatpages/default.html, and you haven't created that yet. The editing form in the admin interface will, if you go back and look for it, also show a field where you can input a different template file name on a per-page basis. So let's pause for a moment and take care of that.

Introducing the Django Template System

Django includes a templating system that has two major design goals:

  • Provide an easy way to express the logic needed for your application's presentation
  • As much as possible, avoid restricting the types of output you can generate

(You can find the templating system in the module django.template, if you've been exploring the Django codebase and want to take a look at it.)

Some template languages allow you to embed nearly any form of programming code directly in the templates. While this can be handy, it also creates a tendency for your application's core programming logic to migrate slowly out of other parts of the code and into the templates, which really ought to confine themselves to the app's presentational aspects. And some templating languages force you to write XML or other specific types of markup, even if what you want to produce isn't XML at all. Django's template system does its best to avoid both of these pitfalls by keeping the allowed programming to a minimum and by not constraining you to specific markup languages. (I've used the Django template system to generate content for e-mail messages and even Excel spreadsheets, for example.)

Ultimately, a Django template file for a web page—in other words, a template whose output is HTML—doesn't end up looking all that different from a normal hand-written web page. The biggest distinction is in two features that the Django template system provides:

  • Variables: A variable is fed to the template by a view—the actual Python function that responds to an HTTP request—and is wrapped in double curly braces, like this: {{ variable_name_here }}. This placeholder is simply replaced with the actual value of the variable.
  • Tags: A tag is wrapped in single curly braces and percent signs, like this: {% tag_name_here %}. Tags can do almost anything, and the exact effect depends on the particular tag. You can also write and use your own custom tags in Django templates, so if there's something you need that isn't provided out of the box, you can add it yourself.

Whenever Django needs a template file, it can look in any of several places, defined by configurable modules called template loaders. By default, Django looks in the following places:

  • Inside any directories specified in your settings module by the setting TEMPLATE_DIRS
  • Inside your installed applications, if any of them include a directory named templates/

These template loaders let you provide a set of default templates with any given application, but also give you the power to override those on a project-by-project basis by listing specific directories you'll put customized templates into. The administrative interface, for example, uses this to great effect: django.contrib.admin contains a templates/ directory with the default templates, but you can add your own templates in a project-specific template directory if you need to customize the admin interface.

Go ahead and choose a directory where you'd like to keep the templates for the simple CMS application. The exact location doesn't matter, as long as it's someplace where you're allowed to create and read files on your computer. Next, open your project's settings.py file, scroll down until you see the TEMPLATE_DIRS setting, and add that directory to the list. Here's mine:

TEMPLATE_DIRS = (
    '/Users/jbennett/html/django-templates/cms/',
)

You'll note that I'm specifying a completely different directory from the one where the project's code is kept. This is often a good practice because it reinforces the idea that the particular presentation—in the form of a set of HTML templates—can and should be decoupled from the back-end code whenever possible. It's also a useful practice for any application you might end up reusing across multiple web sites. Different sites will obviously have different sets of templates, so you'll find it handy to able to switch them at will without needing to move lots of files in and out of a project-specific location.

Now, inside the template directory you chose, create a subdirectory called flatpages/, and in that subdirectory create a new file called default.html. Refresh the flat page in your web browser, and you should see a blank white page. Now you have a template directory specified in your settings, and the file flatpages/default.html exists inside it, so there's no longer an error. But the template file is empty, so it doesn't produce any output. Let's fix that by opening up the default.html file and adding some content:

<html>
    <head>
        <title>{{ flatpage.title }}</title>
    </head>
    <body>
        <h1>{{ flatpage.title }}</h1>
        {{ flatpage.content }}
    </body>
</html>

Now save the file and refresh the page in your web browser again. You should see something like the screen shown in Figure 2-5.

image

Figure 2-5. Your first Django flat page

You'll see that this template uses two variables—flatpage.title and flatpage.content—and no tags. Those variables actually come from a single source: a variable flatpage, which was passed to the template by a Python view function defined inside django.contrib.flatpages. The value of this variable is a FlatPage object, an instance of the data model for flat pages. Django created this object by querying the database for a row with a URL column that matched the URL /first-page/. It then used the data from that row to create a Python object with attributes named title and content, matching what you entered in the admin interface (along with other attributes—url, for example—which aren't as important for the presentational aspect of things).

With this template in place, you now have—literally—a simple dynamic CMS that will let you define as many pages as you'd like, title them, fill in content, and place them at any URL (except URLs starting with admin/ because they'll be matched by the URL pattern for the admin interface). If you wanted to, you could dress up the template with fancier HTML and a nice cascading style sheet (CSS), create a few more user accounts through the administrative interface, and deploy the application onto a live web server for real-world use. But so far, you've written only a couple lines of actual code: the URL pattern for the pages in your urls.py file, a few Django settings, and a little HTML.

Obviously, getting an application up and running with Django won't always be quite this easy, but hopefully you've seen that taking advantage of Django's components can significantly cut down the amount of work you have to do.

Looking Ahead

Pause here for a few moments to play with the simple CMS and explore the Django administrative interface. Take particular note of the Documentation link that appears in the upper-right corner of each page in the admin. It provides automatically generated documentation for all of the data models, URL patterns, and template tags available in your Django project. Not all of it will be immediately understandable at this point, but click around in the documentation area to get a feel for what's in there. When you're developing or working with more complex applications, the admin documentation system will be an important resource for learning about and understanding the code you're using.

When you're ready to get back to work, the next chapter will be waiting for you with a guide to customizing this simple CMS and adding some useful features, including a search function.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset