A Custom form for Django's Automatic Admin.

Published on 2009-01-14 16:08:00+00:00
Python   django   web  

A huge selling-point for Django (at least for developers) is its Automatic Admin. However, the ease at which the Admin can be set up, might make one second-guess an attempt to customize what is provided by default. Of course, the default admin site may not be without its drawbacks...

Many of the django Apps that I have built, tap into Django's User Authentication System. Simply put, when I build a model, it has a Foreign Key to django's User Class.

Here's an example Model:

from django.contrib.auth.models import User  
from django.db import models  
class Book(models.Model):  
    author = models.ForeignKey(User)  
    title = models.CharField()

The problem here is that when I create or edit a Book object using the Automatic Admin, the author field is represented by a select element, whose options contain ALL User objects... listed by username! Wouldn't it be nice if we could have that listed as "firstname lastname" or even as "lastname, firstname"? You can! And here's how:

First of all, Django's admin makes extensive use of ModelForms, and fields with a Foreign Key relationship are represented by a ModelChoiceField. So, all we need to do is extend the ModelChoiceField so that we have something that can be used on any Form that represents a Model with a Foreign Key to a User object. The label_from_instance method accepts an object (in this case, a User object), and returns a string that will be used between

from django.forms import ModelChoiceField  
class UserModelChoiceField(ModelChoiceField):  
    def label\_from\_instance(self, obj):  
        # Return a string of the format: "firstname lastname (username)"  
        return "%s (%s)"%(obj.get_full_name(), obj.username)

Now, create a ModelForm for your Model, which specifies the new Field to be used for the author. Note that we need to pass it a queryset of Users. Below, I've named this ModelForm, BookAdminForm since I'm only going to use this form for the admin pages.

from django.forms import ModelForm  
from django.contrib.auth.models import User  
class BookAdminForm(ModelForm):  
    author = UserModelChoiceField(User.objects.all().order_by('first\_name'))  
    class Meta:  
        model = Book

Now we set up the ModelAmin for the Book Model. In it, we can specify the form that is used by Django's automatic admin (Note that this MUST be a ModelForm!). Your admin would look something similar to the following:

from django.contrib import admin  
from forms import BookAdminForm  
from models import Book  
class BookAdmin(admin.ModelAdmin):  
    form = BookAdminForm  
admin.site.register(Book, BookAdmin)

Now, when you use the Automatic admin to add or edit existing Book entries, the drop-down list of Author names will be a bit more user-friendly.