This is one learning note of the Django admin interface. The following list is the skill points we should know or master it.

The Django’s automatic admin interface is one of the most powerful parts. It automatically reads metadata from models to provide a fast, model-centric interface. Then wen can manage content on the website by the Django admin interface.

When we built one web project based on Django, Django automatically created an admin interface for us. It greatly reduces the workload of the development management background.

There are many methods provided in the admin interface, let’s learn about them.

#1 ModelAdmin objects


The ModelAdmin object in Django represents the model in the admin interface. Usually, the admin interface methods located in the admin.py file.

You should use the register decorator to register ModelAdmin classes. The format as following, it can be registered to one or more model classes. Note that: use the site keyword argument to register for the custom AdminSite.

from django.contrib import admin
from .models import Author, Editor, Reader
from myproject.admin_site import custom_admin_site

@admin.register(Author, Reader, Editor, site=custom_admin_site)
class PersonAdmin(admin.ModelAdmin):
    pass

#2 ModelAdmin.save_model()


The save_model method can help to do pre- or post-save operations when adding or changing the object, then to save the object. Check out the official definition of save_model.

The save_model method is given the HttpRequest, a model instance, a ModelForm instance, and a boolean value based on whether it is adding or changing the object. Overriding this method allows doing pre- or post-save operations. Call super().save_model() to save the object using Model.save().

For example, you want to attach the user of the object being adding or editing to the request.user.

from django.contrib import admin

class ArticleAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        super().save_model(request, obj, form, change)

The obj is the object being adding or changing then will be saved. The request.user is the user who login currently, and the form is the form object received.

#3 ModelAdmin.list_display


The ModelAdmin.list_display is used to set which fields are displayed on the change list page.

If the list_display is not set, then default display a single column with the returned value of __str__() of each object.

@admin.register(Post, site=custom_site)
class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'category', 'status', 'owner', 'created_time', 'operator')

When there are ForeignKey in list_display, the related object should be overwritten the __str__() method. If not, it will be displayed like this ‘Category object (3)’.

How to add customed fields into the list_display?

You can add customed fields representing a customed method or model attribute. Note that the method should without any required arguments.

For example, we add the Edit field into the above list_display.

from django.urls import reverse
from django.utils.html import format_html
    
def operator(self, obj):
        return format_html(
            '<a href="{}">Edit</a>',
            reverse('cus_admin:blog_post_change', args=(obj.id,))
        )
    operator.short_description = 'Operator'

#4 ModelAdmin.fields & fieldsets


Two functions of ModelAdmin.fields. 1) to make sure which fields display, 2) the order of displayed fields in both the “add” and “change” pages.

Note that: Don’t confuse fields option with the fields dictionary key that is within the fieldsets option.

ModelAdmin.fieldsets is used to set the layout of admin “add” and “change” pages

fieldsets is a list of two-tuples, in which each two-tuple represents a <fieldset> on the admin form page. (A <fieldset> is a “section” of the form.)

The two-tuples are in the format (name, field_options), where name is a string representing the title of the fieldset and field_options is a dictionary of information about the fieldset, including a list of fields to be displayed in it.

For example:

class FlatPageAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {
            'fields': ('url', 'title', 'content', 'sites')
        }),
        ('Advanced options', {
            'classes': ('collapse',),
            'fields': ('registration_required', 'template_name'),
        }),
    )

#5 InlineModelAdmin objects


Django admin interface provides InlineModelAdmin objects to make it have the ability to edit other models on the same page.

InlineModelAdmin with two subclasses:

  • TabularInline
  • StackedInline

For example, you can edit Post on the Category page.

class PostInline(admin.TabularInline):
    fields = ('title', 'desc')
    extra = 1
    model = Post

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    ...
    inlines = (PostInline,)
    ...

#6 SimpleListFilter


You can design a class inheriting from SimpleListFilter to activate filters in the right sidebar of the change list page.

In your class, you need to provide the title and parameter_name attributes. And also to override the lookups and queryset methods.

For example:

class CategoryOwnerFilter(admin.SimpleListFilter):
    # Human-readable title which will be displayed in the
    # right admin sidebar just above the filter options.
    title = 'Category Filter'
    # Parameter for the filter that will be used in the URL query.
    parameter_name = 'owner_category'
    
    #Return a list of tuples.
    #1)The first element(id) stands for the coded value for the 
    #      option that will appear in the URL query
    #2)The second element(name) is the human-readable name for 
    #      the option that will appear in the right sidebar.
    def lookups(self, request, model_admin):
        return Category.objects.filter(owner=request.user)
               .values_list('id', 'name')

    def queryset(self, request, queryset):
        category_id = self.value()
        if category_id:
            return queryset.filter(id=category_id)
        return queryset
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    ...
    list_filter = (CategoryOwnerFilter,)
    ...

#7 How to include static resources?


Django provides an interface for us to include static resources into projects.

For example, to include the CSS and js resources of bootstrap 4.

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    ...
    class Media:
        css = {
            'all': ('href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css', ),
        }
        js = ('https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js', )

     ...

References