Customizing StaffMember

While the StaffMember model is meant to be general, sometimes you need something extra. You can create your own subclass of StaffMember for tweaking. In the example project you can browse the mystaff app. To test it out:

  1. Comment out 'staff', from INSTALLED_APPS in settings.py
  2. Uncomment 'mystaff', from INSTALLED_APPS in settings.py
  3. Delete the dev.db file
  4. Run ./manage.py syncdb
  5. Create a new superuser when prompted

Create the custom class

Your custom StaffMember model is going to subclass BaseStaffMember, which is an abstract version of StaffMember. Add your additional fields to the class.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from django.db import models
from django.db.models.signals import post_save
from django.contrib.auth.models import User

from staff.models import BaseStaffMember, get_staff_updater

class MyStaffMember(BaseStaffMember):
    github = models.CharField(max_length=50, blank=True)


update_staff_member = get_staff_updater(MyStaffMember)
post_save.connect(update_staff_member, sender=User)

Connect the signal

You need to manually connect the post_save signal to a function that keeps your custom staff member class in sync.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from django.db import models
from django.db.models.signals import post_save
from django.contrib.auth.models import User

from staff.models import BaseStaffMember, get_staff_updater

class MyStaffMember(BaseStaffMember):
    github = models.CharField(max_length=50, blank=True)


update_staff_member = get_staff_updater(MyStaffMember)
post_save.connect(update_staff_member, sender=User)
  1. Import get_staff_updater() from staff.models. See line 5 in the example.
  2. Execute it, passing in your model, and assign it to a variable. See line 11 in the example.
  3. Import post_save from django.db.models.signals. See line 2 in the example.
  4. Finally connect the post_save signal to your staff updater variable as in line 12 in the example.

Create your admin class

The admin class is more complicated. It consists of three parts: customizing the StaffMemberAdmin class, creating a custom UserAdmin, and finally swapping out the currently registered UserAdmin class with yours.

Your own admin class

Your admin class simply needs to redefine the fieldsets and model of the StaffMemberAdmin class.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from django.contrib import admin
from staff.admin import StaffMemberAdmin

from .models import MyStaffMember


class MyStaffMemberAdmin(StaffMemberAdmin):
    fieldsets = (
        ('Personal Info', {'fields': ('bio', 'photo', 'website', 'phone',)}),
        ('Social Media', {'fields': ('github', 'twitter', 'facebook', 'google_plus')}),
        ('Responsibilities', {'fields': ('sites',)}),
    )
    model = MyStaffMember

class MyStaffUserAdmin(UserAdmin):
    """
    Subclasses the UserAdmin to add the staffmember as an inline.
    """
    inlines = [MyStaffMemberAdmin, ]

admin.site.unregister(User)
admin.site.register(User, MyStaffUserAdmin)

The class is very straightforward. Since we only added one field, github, we copy the fieldsets value from the base class and add that field in.

Then we set the model to our new model.

Making a custom User admin class

We need to add an inline class to the current UserAdmin.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from django.contrib import admin
from staff.admin import StaffMemberAdmin

from .models import MyStaffMember


class MyStaffMemberAdmin(StaffMemberAdmin):
    fieldsets = (
        ('Personal Info', {'fields': ('bio', 'photo', 'website', 'phone',)}),
        ('Social Media', {'fields': ('github', 'twitter', 'facebook', 'google_plus')}),
        ('Responsibilities', {'fields': ('sites',)}),
    )
    model = MyStaffMember

class MyStaffUserAdmin(UserAdmin):
    """
    Subclasses the UserAdmin to add the staffmember as an inline.
    """
    inlines = [MyStaffMemberAdmin, ]

admin.site.unregister(User)
admin.site.register(User, MyStaffUserAdmin)

This is merely sublassing the existing UserAdmin and adding our own inlines attribute equal to a list containing the new admin class defined above.

Re-registering the UserAdmin

Now we carefully swap the old UserAdmin with our UserAdmin subclass.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from django.contrib import admin
from staff.admin import StaffMemberAdmin

from .models import MyStaffMember


class MyStaffMemberAdmin(StaffMemberAdmin):
    fieldsets = (
        ('Personal Info', {'fields': ('bio', 'photo', 'website', 'phone',)}),
        ('Social Media', {'fields': ('github', 'twitter', 'facebook', 'google_plus')}),
        ('Responsibilities', {'fields': ('sites',)}),
    )
    model = MyStaffMember

class MyStaffUserAdmin(UserAdmin):
    """
    Subclasses the UserAdmin to add the staffmember as an inline.
    """
    inlines = [MyStaffMemberAdmin, ]

admin.site.unregister(User)
admin.site.register(User, MyStaffUserAdmin)

Django’s admin has the ability to both register an admin class and unregister an admin class. After removing any admin classes associated with the User class, we register and associate our custom user admin class.

Gather the templates

Django staff includes a set of templates for various Django versions. Since we’ll remove 'staff' from INSTALLED_APPS, Django won’t find them any more. We need to copy them into either the project’s templates directory or your application’s template directory.

The templates, named staff.html and staff13.html, need to go into:

templates
   admin
      edit_inline
         staff.html
         staff13.html

Remove staff from INSTALLED_APPS

If Django Staff is still included in your INSTALLED_APPS setting, you’ll have a bit of redundancy. Make sure that 'staff' is not in that list. It still must remain available to your new application, so don’t don’t uninstall the library.