Putting the admin to use
We have a working model and an admin that allows us to interface with its data. It’s functional and looks pretty, but it’s still not terribly helpful. Let’s soldier forth.
Managing Users and Permissions- First thing first. You’ll notice you have a built-in app (providing django.contrib.auth was installed, as it should be) that includes two editable models: groups and users. This is, amazingly, where you can control groups and users.
It should be pretty intuitive. Dive into the “users” model and add a test account. Save that and you’ll be taken to a second page where you see how customizable each account can be. Here’s a quck rundown of what everything does:
- The user’s first name, last name and e-mail address are not required, but can be nice to have on hand.
- In order to log in, a person has to be both staff and active, so both those boxes have to be checked.
- Superuser status gives a permission full permission to do everything. They can add and edit anything that shows up in any app. Be careful in giving someone this level of access.
- Finally, we reach “User permissions.” This is the meat of any CRUD interface. Each model has three different levels of access that a user can have: Add, Change and Delete. They do exactly what you think they should do. Any user with Add permission can add entries to the model. Any user with Change permission cannot add a new listing, but can make changes to any existing entry. A user with Delete permission can’t add or change anything, but can zap anything from the system.
Obviously, it doesn’t make sense to give these out one by one. The most common permission, I’d say, gives users the ability to Add and Change any entry.
Displaying information in the model admin- In the previous post, anything we added to the “High Schools” model was displayed as “HighSchool object,” which is about the least useful name for anything ever. This is easy to address.
Edit you admin.py file to look like this:
//admin.py
...
class HighSchoolAdmin(admin.ModelAdmin):
list_display = ('name',)
admin.site.register(HighSchool, HighSchoolAdmin)
All we did there was access the list_display property of our ModelAdmin and tell it to how us the name of the school. Access that model admin section again, and you’ll see “HighSchool object” now reads the actual name of your school. Adding other fields to the page is just a matter of stringing field names together in the same format. For example, an admin displaying all of our fields would just require:
//admin.py
...
list_display = ('name', 'principal', 'enrollment', 'website')
The order you call them in here denotes the order they appear in the admin.
Making the model admin searchable- Making your model searchable is similarly easy to execute. Again, it requires only one line in the admin:
//admin.py
...
class HighSchoolAdmin(admin.ModelAdmin):
search_fields = ('name', 'principal')
admin.site.register(HighSchool, HighSchoolAdmin)
Put that in your pipe and smoke it. When you reload the High School page, you’ll see a handy-dandy search box that will search the values of the school name and principal fields.
By default, searches are enclosed in wild cards. So searching for “Smith,” in this example, will return both John Smith High school as well as principal Hymie Goldsmith.
Making fields optional - There is a lot more that can be done with admin.py, but more common problems seem to crop up at the individual record level. Many of these issues need to be addressed in models.py. For instance, let’s say we get three records into our project before we realize that private schools don’t have principals. As things stand, any attempt to leave that field blank will be met with a stern warning from Django saying the Principal field is required.
To make the field optional, we’ll add an argument to its entry in models.py like so:
//models.py
class HighSchool(models.Model):
name = models.CharField(max_length=50)
principal = models.CharField(max_length=50, blank=True)
enrollment = models.IntegerField()
website = models.URLField(verify_exists=True, max_length=120)
Explicitly allowing blanks means the field is now optional. On the “Add High School” page, you’ll notice the name of the field is in regular typeface as opposed to bold.
Adding some signposts- In my experience, the Django admin is significantly more intuitive than PHPMyAdmin. But that’s still not always enough. Sometimes you need to be able to give your users hints along the way.
This, too, is an easy addition. Let’s say we’ve received a frenzied e-mail from our well-intentioned temp saying he doesn’t know what to put in the “Enrollment” field. He has different counts for each grade, he says, but when he tried to list them, he gets an error saying “Enter a whole number.” Help?
Let’s dive back into models.py and add some help text:
//models.py
class HighSchool(models.Model):
name = models.CharField(max_length=50)
principal = models.CharField(max_length=50, blank=True)
enrollment = models.IntegerField(help_text="Enter one value for the whole school.")
website = models.URLField(verify_exists=True, max_length=120)
Well hot damn. Out handy-dandy little signpost has been cleanly inserted right under our field, making this thing all but idiot proof. At this point, clicking the “Add High School” button should give you something much like this:

For next time
Between these two posts, you should have enough to rapidly build some simple data entry tools for brand new datasets your organization creates on its own.
Of course, that’s not usually the case. Often, especially in journalism, we need to interface with existing data. Our next installment will cover how to get our arms around legacy datasets and get them into our system.
This entry was posted on Monday, March 8th, 2010 at 8:57 pm and is filed under Uncategorized. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
Have your say
Fields in bold are required. Email addresses are never published or distributed.
Some HTML code is allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>URIs must be fully qualified (eg: http://www.domainname.com) and all tags must be properly closed.
Line breaks and paragraphs are automatically converted.
Please keep comments relevant. Off-topic, offensive or inappropriate comments may be edited or removed.