Member Sign In
Not a member?

A Wired.com user account lets you create, edit and comment on Webmonkey articles. You will also be able to contribute to the Wired How-To Wiki and comment on news stories at Wired.com.


It's fast and free.

Webmonkey is a property of Wired Digital.
processing...
Join Webmonkey

Please send me occasional e-mail updates about new features and special offers from Wired/Webmonkey.
Yes No

Please send occasional e-mail offers from Wired/Webmonkey affiliated web sites and publications, and carefully selected companies.
Yes No

I understand and agree that registration on or use of this site constitutes agreement to Webmonkey's User Agreement and Privacy Policy.
Webmonkey is a property of Wired Digital.
processing...

Retrieve Sign In

Please enter your e-mail address or username below. Your username and password will be sent to the e-mail address you provided us.

or
Webmonkey is a property of Wired Digital.
processing...

Welcome to Webmonkey

A private profile page has been created for you.
As a member of Webmonkey, you can now:
  • edit articles
  • add to the code library
  • design and write a tutorial
  • comment on any Webmonkey article
Close
Webmonkey is a property of Wired Digital.

Sign In Information Sent

An e-mail has been sent to the e-mail address registered in this account.
If you cannot find it in your in-box, please check your bulk or junk folders.
Sign In
Webmonkey is a property of Wired Digital.

Django Newforms Admin Migration

/skill level/
/viewed/
0 Times

If you've been following our Django tutorials since they first started, you may be wondering about the recent news that the NewForms Admin branch of Django was recently merged to trunk.

What does that mean? It means that if you update your svn checkout of Django, it's going to break all the code we wrote earlier. But don't worry, the changes aren't too radical and adjusting our code takes only a few minutes.

The goal of the NewForms Admin branch was two-fold. First, the developers wanted to make sure that the admin app (which is a stand-alone app that ships with Django) used the latest Django froms code (hence the NewForms bit of the name). The other goal was to decouple the admin and make it much easier to customize.

We're not going to dive into customizations (see the updated Django docs if you're itching to know more details), but let's take a look at what we need to do to port our code over to the latest version of Django.

First, make sure you have the latest version of Django. Fire up your terminal and cd over to your Django folder. Then run svn up and Django will update itself.

Contents

Decoupling

The first thing we need to do is create a new file in our blog app folder named "admin.py". As part of the decoupling, our model's admin definitions now live in seperate file, which makes sense since the old Admin class really had nothing to do with the model.

So let's open up the admin.py file and re-write our admin class definition. Our old code, where the Admin class lived in model.py looked something like this (I've left out a few things for clarity):

class Entry(models.Model):
    """
    ...all the field definitions omitted...
    """
    
    class Meta:
        ordering = ('-pub_date',)
        get_latest_by = 'pub_date'
        verbose_name_plural = 'entries'

    class Admin:
        list_display = ('title', 'pub_date','enable_comments', 'status',)        
        search_fields = ['title', 'body_markdown']
        list_filter = ('pub_date', 'enable_comments', 'status')
        fields = (
            (None, {
                'fields': (('title', 'status'), 'body_markdown', ('pub_date', 'enable_comments'), 'tags', 'slug')
            }),
        )

Now the Meta class remains part of the models.py file, since it controls model-related behavior. But the Admin class really doesn't relate directly to the model. So, open up blog/models.py and cut all that data out. Our models.py file should now looks like:

class Entry(models.Model):
    title = models.CharField(max_length=200)
    slug = models.SlugField(
        unique_for_date='pub_date',
        help_text='Automatically built from the title.'
    )
    body_html = models.TextField(blank=True)
    body_markdown = models.TextField() #note, if you're using Markdown, include this field, otherwise just go with body_html
    pub_date = models.DateTimeField('Date published')
    tags = TagField()
    enable_comments = models.BooleanField(default=True)
    PUB_STATUS = (
        (0, 'Draft'),
        (1, 'Published'),
    )
    status = models.IntegerField(choices=PUB_STATUS, default=0)
    
    class Meta:
        ordering = ('-pub_date',)
        get_latest_by = 'pub_date'
        verbose_name_plural = 'entries'

    def __unicode__(self):
        return u'%s' %(self.title)

    def get_absolute_url(self):
        return "/%s/%s/" %(self.pub_date.strftime("%Y/%b/%d").lower(), self.slug)
    
    def save(self):
         self.body_html = markdown.markdown(self.body_markdown, safe_mode = False)
         super(Entry, self).save()

Note that we also deleted the prepopulate_from field in the slug definition. That's another thing that's moved over to the new admin.py file.

OK, now we need to define our Admin class according to the new conventions. Jump back to the new admin.py and paste in this code:

from django.contrib import admin

from djangoblog.blog import Entry

class EntryAdmin(admin.ModelAdmin):
    list_display = ('title', 'pub_date','enable_comments', 'status')           
    search_fields = ['title', 'body_markdown']
    list_filter = ('pub_date', 'enable_comments', 'status')
    prepopulated_fields = {"slug" : ('title',)}
    fields = (
		(None, {'fields': (('title', 'status'), 'body_markdown', ('pub_date', 'enable_comments'), 'tags', 'slug')}),
    )

admin.site.register(Entry, EntryAdmin)


So what's different?

First off, we imported the admin module and extended the ModelAdmin class with our own EntryAdmin class. Then we brought over the same definitions we use above to control list_display, search_fields and list_filter. Then we use one brand new bit of syntax. Remember in our original model we used prepopulate_from to automatically fill our slug field with whatever is typed in our title field?

Well the new name is prepopulated_fields and instead of a string, it's now a dictionary. The key is the field to fill and the value is where to pull from. Obviously, since it's a dictionary you could add several fields if need be.

The fields customizations remain the same in our case, though there is a new fieldsets option if you want to have several sets of fields (duh).

The last line of our code just registers our new Admin class and lets Django know that whenever it's displaying info about our Entry model, it should follow the rules we set up in EntryAdmin.

See, that wasn't so bad.

New URL structures

As I said earlier, one of the main goals with NewForms Admin was to make the Django admin more flexible. Part of the way that's achieved is through the urls.py file. So, open up our project level urls.py file and you should see something like this:

urlpatterns = patterns('',
    # Example:
    # (r'^djangoblog/', include('djangoblog.foo.urls')),
     (r'^admin/(.*)', include('django.contrib.admin.urls')),
)

We're going to change that to this:

from django.conf.urls.defaults import *
from django.contrib import admin

admin.autodiscover()


urlpatterns = patterns('',
     (r'^admin/(.*)', admin.site.root),
     ... the rest stays the same...
)

Notice that we're no longer simply handing off all the admin URLs to a mysterious include statement. That means we could concievably create all sorts of URLs and pass them to our own custom views. In fact, you could have several different admin sites if you so desired.

Updating tagging

The last step in our transition to NewForms Admin is to update our django-tagging application. As of this writing, django-tagging hasn't caught up to the newforms admin update yet, so we're actually going to need to checkout the Newforms Admin branch of the django-tagging codebase.

To do that, we'll grab the files using Subversion. Paste this code into your terminal window:

svn checkout http://django-tagging.googlecode.com/svn/branches/newforms-admin django-tagging

Now cd into the new django-tagging folder and type:

python setup.py install

After that, just delete the old version.

If you're good with Subversion, there are other ways to do this. Feel free to add your own instructions for alternate methods to this wiki page.


Other changes

There are quite a few other changes to the admin section, and if you have a lot of old code to port definitely head over and check out the new documentation.

Also highly recommended is Brian Rosner's very informative screencast which covers inlines and some other more complicated things our project isn't using.

  • This page was last modified 20:39, 8 August 2008.
Edit this article
Reddit Digg
 
Subscribe now

Special Offer For Webmonkey Users

WIRED magazine:
The first word on how technology is changing our world.

Subscribe for just $10 a year