Django Newforms Admin Migration
/skill level/
/viewed/
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.