The Django Book

You're reading an outdated version of this book; a newer version is available.

Chapter 6: The Django admin site

There’s one part of Web development we’ve always hated: writing administration interfaces. Developing the parts of the site that the general public sees is always different and interesting, but the bits that the administrators use to modify the site are always the same. You’ve got to deal with authenticating users, display and handle forms, deal with tricky validation issues… It’s boring, and it’s repetitive.

Django’s approach to this boring, repetitive task? Do it all for you — in just a couple of lines of code, no less.

One of the oldest and most powerful parts of Django is the automatic admin interface. It hooks off of metadata in your model to provide a powerful and production-ready interface that content producers can immediately use to start adding content to the site.

Activating the admin interface

We think the admin interface is the coolest part of Django — and most Djangonauts agree — but since not everyone actually needs it, it’s an optional piece. That means there are three steps you’ll need to follow to activate the admin interface:

  1. Add admin metadata to your models.

    Not all models can (or should) be editable by admin users, so you need to “mark” models that should have an admin interface. You do that be adding an inner Admin class to your model (alongside the Meta class, if you have one). So, to add an admin interface to our Book model from the previous chapter:

    class Book(models.Model):
        title = models.CharField(maxlength=100)
        authors = models.ManyToManyField(Author)
        publisher = models.ForeignKey(Publisher)
        publication_date = models.DateField()
    
        class Admin:
            pass
    

    The Admin declaration flags the class as having an admin interface. There are a number of options that you can put beneath Admin, but for now we’re sticking with all the defaults, so we put pass in there to signify to Python that the Admin class is empty.

    If you’re following this example with your own code, it’s probably a good idea to add Admin declarations to the Publisher and Author classes at this point.

  2. Install the admin models. Simply add "django.contrib.admin" to your INSTALLED_APPS setting and run python manage.py syncdb to install the extra tables the admin uses.

    Note

    When you first ran syncdb, you were probably asked about creating a superuser. If you didn’t that time, you’ll need to run django/contrib/auth/bin/create_superuser.py to create an admin user. Otherwise you won’t be able to log into the admin interface.

  3. Add the URL pattern to your urls.py. If you’re still using the one created by startproject, the admin URL pattern should be already there, but commented out. Either way, your URL patterns should look like:

    from django.conf.urls.defaults import *
    
    urlpatterns = patterns('',
        (r'^admin/', include('django.contrib.admin.urls')),
    )
    

That’s it. Now run python manage.py runserver to start the development server; you’ll see something like:

Validating models...
0 errors found.

Django version 0.96-pre, using settings 'ch6.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Now you can visit the URL given to you by Django (http://127.0.0.1:8000/admin/ in the example above), log in, and play around.

Using the admin interface

The admin interface is designed to be used by non-technical users, and as such should be pretty self-explanatory. Nevertheless, a few notes about the features of the admin are in order.

The first thing you’ll see is a login screen:

Screenshot of Django’s login page.

You’ll use the username and password you set up when you first ran syncdb here. Once you’ve logged in, you’ll see that you can manage users, groups, and permissions in the admin; see more on that below.

Each object given an Admin declaration shows up on the main index page. Links to add and change objects lead to two pages we refer to as object “change lists” and “edit forms”:

Screenshot of the main Django admin index..

Change lists are essentially index pages of objects in the system:

Screenshot of a typical change list view.

There are a number of options that can control which fields appear on these lists and the appearance of extra features like date drill downs, search fields, and filter interfaces. There’s more about these features below.

Edit forms are used to edit existing objects and create new ones. Each field defined in your model appears here, and you’ll notice that fields of different types get different widgets (i.e. date/time fields have calendar controls; foreign keys use a select box, etc.):

Screenshot of a typical edit form.

You’ll notice that the admin also handles input validation for you; try leaving a required field blank, or putting an invalid time into a time field and you’ll see those errors when you try to save:

Screenshot of an edit form displaying errors.

This validation actually is done with a powerful validation framework which is discussed in Chapter 7.

When editing an existing object, you’ll notice a “history” link in the upper-right. Every change made through the admin is logged, and you can examine this log by clicking the history button:

Screenshot of Django’s object history page.

Deletions in the admin cascade. That is, when deleting an existing object, you’ll see that the admin asks you to confirm the delete action to avoid costly mistakes. What might not be instantly obvious is that this page will show you all the related objects that will be deleted as well:

Screenshot of Django’s delete confirmation page.

Users, groups, and permissions

Since you’re logged in as a superuser, you have access to create, edit, and delete any object. However, the admin has a user permissions system that you can use to give other users access only to the portions of the admin they need.

You edit these users and permissions through the admin just like any other object; the link to the User and Group models is there on the admin index along with all the objects you’ve defined yourself.

User objects have the standard username, password, email, and real name fields you might expect, along with a set of fields that define what the user is allowed to do in the admin. First, there’s a set of three flags:

  • The “is active” flag controls whether the user is active at all. If this flag is off, the user has no access to any URLs that require login.
  • The “is staff” flag controls whether the user is allowed to log into the admin (i.e. is considered a “staff member” in your organization). Since this same user system can be used to control access to public (i.e. non-admin) sites (see Chapter 12), this flag differentiates between public users and administrators.
  • The “is superuser” flag gives the user full unfettered access to every item in the admin; regular permissions are ignored.

For “normal” admin users — active, non-superuser staff members — the access they are granted depends on a set of assigned permissions. Each object editable through the admin has three permissions: a “create” permission, an “edit” permission, and a “delete” permission. Assigning permissions to a user grants the user access to do what is described by those permissions.

Note

Notice that access to edit users and permissions is also controlled by this permission system. If you give a user permission to edit users, she will be able to edit her own permissions, which might not be what you want!

You can also assign users to groups. A group is simply a set of permissions to apply to all members of that group. Groups are extremely useful for granting a large number of users identical permissions.

Customizing the admin interface

There are a number of ways to customize the way the admin interface looks and behaves. We’ll cover just a few of them below as they relate to our `` Book`` model, but Chapter 12 covers customizing the admin interface in detail.

As it stands now, the change list for our books show only the string representation of the model we added to its __str__. This works fine for just a few books, but if we had hundreds or thousands of books, it would be very hard to locate a single needle in the haystack. However, we can easily add some display, searching, and filtering functions to this interface. Change the Admin declaration to:

class Book(models.Model):
    title = models.CharField(maxlength=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

    class Admin:
        list_display   = ('title', 'publisher', 'publication_date')
        list_filter    = ('publisher', 'publication_date')
        ordering       = ('-publication_date',)
        search_fields  = ('title',)

These four lines of code dramatically change our list interface:

Screenshot of the modified change list page.

Each of those lines instructed the admin to construct a different piece of this interface:

  • The ordering option controls what order the objects are presented in the admin. It’s simply a list of fields to order the results by; prefixing a field with a minus sign reverses the given order. So in this example, we’re ordering by publication date, most recent first.

  • The list_display option controls which columns appear in the change list table. By default, only a single column with the object’s string representation appears; here we’ve changed that to show the title, publisher, and publication date.

  • The list_filter option creates the filtering bar on the right side of the list. We’ve allowed filtering either by date (which allows you to see only books published in the last week, month, etc.), and by publisher.

    You can instruct the admin to filter by any field, but foreign keys or any field with a choices attribute set work best.

  • Finally, the search_fields option creates a field that allows text searches. This allows searches by the title field (so you could type “Django” to show all books with “Django” in the title).

Using these options — and the other ones described in Chapter 12 — you can with only a few lines of code make a very powerful, production-ready interface for data editing.

Customize the admin look and feel

Clearly, having “Django administration” at the top of each admin page is ridiculous. It’s just placeholder text.

That’s easy to change, though, using Django’s template system. The Django admin is powered by Django itself, and its interfaces use Django’s own template system. (How meta!)

Open your settings file (mysite/settings.py, remember) and look at the TEMPLATE_DIRS setting. TEMPLATE_DIRS is a tuple of filesystem directories to check when loading Django templates. It’s a search path.

By default, TEMPLATE_DIRS is empty. So, let’s add a line to it, to tell Django where our templates live:

TEMPLATE_DIRS = (
    "/home/mytemplates", # Change this to your own directory.
)

Note

Make sure to include the trailing comma there — Python uses it to distinguish between single-element tuples and parenthesized expressions.

Now copy the template admin/base_site.html from within the default Django admin template directory (django/contrib/admin/templates) into an admin subdirectory of whichever directory you’re using in TEMPLATE_DIRS. For example, if your TEMPLATE_DIRS includes "/home/mytemplates", as above, then copy django/contrib/admin/templates/admin/base_site.html to /home/mytemplates/admin/base_site.html. Don’t forget that admin subdirectory.

Then, just edit the new admin/base_site.html file to replace the generic Django text with your own site’s name as you see fit.

Note that any of Django’s default admin templates can be overridden. To override a template, just do the same thing you did with base_site.html — copy it from the default directory into your custom directory and make changes to the copy.

Astute readers wonder how, if TEMPLATE_DIRS was empty by default, Django was finding the default admin templates? The answer is that, by default, Django automatically looks for templates within a templates/ subdirectory in each app package as a fallback. See “Template loaders” in Chapter 10 for more information about how this works.

Customize the admin index page

On a similar note, you might want to customize the look and feel of the Django admin index page.

By default, it displays all available apps, according to your INSTALLED_APPS setting, sorted by the name of the application. You might, however, want to change this order to make it easier to find the apps you’re looking for. After all, the index is probably the most important page of the admin, so it should be easy to use.

The template to customize is admin/index.html. (Remember to copy admin/base_site.html to your custom template directory as in the previous example.) Edit the file, and you’ll see it uses a template tag called {% get_admin_app_list as app_list %}. That’s the magic that retrieves every installed Django app. Instead of using that, you can hard-code links to object-specific admin pages in whatever way you think is best. If hard-coding links doesn’t appeal to you, you can also see Chapter 10 for details on implementing your own template tags.

Django offers another shortcut in this department. Run the command python manage.py adminindex <app> to get a chunk of template code for inclusion in the admin index template. It’s a useful starting point.

For full details on customizing the look and feel of the Django admin site in general, see Chapter 12.

When and why to use the admin interface

We think Django’s admin interface is pretty spectacular. In fact, we’d call it one of Django’s “killer features”. However, we often get asked questions about “use cases” for the admin — when do we use it, and why? Over the years, we’ve discovered a number of patterns for using the admin interface that we think might be helpful.

Obviously, it’s extremely useful for editing data (fancy that). If you have any sort of data entry tasks, the admin simply can’t be beat. We suspect that the vast majority of readers of this book will have a whole host of data entry tasks.

Django’s admin especially shines when non-technical users need to be able to enter data; that’s the original genesis of the feature. At the newspaper where Django was first developed, development of a typical online feature — a special report on water quality in the municipal supply, say — goes something like this:

  • The reporter responsible for the story meets with one of the developers and goes over the available data.
  • The developer designs a model around this data, and then opens up the admin interface to the reporter.
  • While the reporter enters data into Django, the programmer can focus on developing the publicly-accessible interface (the fun part!)

In other works, the raison d’ĂȘtre of Django’s admin is facilitating the simultaneous work of content producers and programmers.

However, beyond the obvious data-entry tasks, we find the admin useful in a few other cases:

  • Inspecting data models: the first thing we do when we’ve defined a new model is to call it up in the admin and enter some dummy data. This is usually when we find any data modeling errors; having a graphical interface to a model quickly reveals those mistakes.
  • Managing acquired data: there’s little actual data entry associated with a site like chicagocrime.org since most of the data comes from an automated source. However, when problems with the automatically acquired data crop up, it’s very useful to be able to go in and edit that data easily.

What’s next?

So far we’ve created a few models and configured a top-notch interface for editing that data. In the next chapter, we’ll move onto the real “meat and potatoes” of Web development: form creation and processing.

So grab another cup of your favorite beverage and let’s get started.

Copyright 2006 Adrian Holovaty and Jacob Kaplan-Moss.
This work is licensed under the GNU Free Document License.
Hosting graciously provided by media temple
Comments X

Comments are closed on this chapter.

We're no longer accepting comments on this version of this chapter.

Many thanks to all those who commented.

      About this comment system

      This site is using a contextual comment system to help us gather targeted feedback about the book. Instead of commenting on an entire chapter, you can leave comments on any indivdual "block" in the chapter. A "block" with comments looks like this:

      A "block" is a paragraph, list item, code sample, or other small chunk of content. It'll get highlighted when you select it:

      To post a comment on a block, just click in the gutter next to the bit you want to comment on:

      As we edit the book, we'll review everyone's comments and roll them into a future version of the book. We'll mark reviewed comments with a little checkmark:

      Please make sure to leave a full name (and not a nickname or screenname) if you'd like your contributions acknowledged in print.

      Many, many thanks to Jack Slocum; the inspiration and much of the code for the comment system comes from Jack's blog, and this site couldn't have been built without his wonderful YAHOO.ext library. Thanks also to Yahoo for YUI itself.