Specify a custom manager for the Django admin interface

django-adminAs I was running through the weblog example in James Bennett’s excellent “Practical Django Projects (2nd Ed)” book I ran across a problem. In the book, we are asked to create a custom manager for the Entry model.

Instead of pulling all entries, the custom manager only pull the entries that have been marked as LIVE (and ignores the ones that are marked HIDDEN or DRAFT).

This custom manager is set as the _default_manager (by defining it first in the Entry class), which is fine, except for the fact that the Django admin interface “defaults” to using the default manager of a class. In the admin, I want to see and edit ALL objects, not just the live ones.

To further complicate things, we create a custom tag that takes any type of content and displays the most recent elements of it. This tag is model agnostic and so uses the _default_manager of the model that it is looking at. So, for the Entry model, the default manager needs to remain the custom one which shows only LIVE results.

Luckily, there is a fairly simple way to tell the admin interface to not use the default manager. Simply change your ModelAdmin class in you admin.py file from something like this:

class EntryAdmin(admin.ModelAdmin):
    prepopulated_fields = { 'slug': ['title'] }

To something like this:

class EntryAdmin(admin.ModelAdmin):
     prepopulated_fields = { 'slug': ['title'] }
     def queryset(self, request):
         return Entry.objects

And make sure that your Entry model has its managers defined thusly:

# Give the Entry model two managers. NOTE: the first one is the default!
live = LiveEntryManager()   # _default_manager #
objects = models.Manager()

Now everywhere that you use Entry.live.all() or Entry._default_manager.all() You’ll pull only the LIVE results while the admin interface will show all of the LIVE, DRAFT and HIDDEN results.

(Let me know in the comments any unspeakable horrors this solution might stir up 😉