Advanced configuration

From registered models, Django automatically includes record indentification via the model’s __str__() method. This also includes a bulk delete operation for records of a particular model.

However, Django also gives us the ability to further customise the interface. We can do things like:

  • List views
    • Add additional fields or information for each record
    • Add filters to select records
    • Add additional options to the actions menu, as well as choose where the menu is
  • Detail views
    • Choose which fields to display, which to exlucde, their order, grouping, etc.
    • Add related fields to a record to allow inline editing

Register ModelAdmin class

To change how a model is displayed on the admin interface we must define and register a ModelAdmin class, which is used to define the layout of the admin site.

For example, given the Terminus Library Author model, we can do the following:

# filename: terminus/catalog/admin.py
 
# Defining admin class
class AuthorAdmin(admin.ModelAdmin):
	pass
 
# Register the admin class with an associated admin moodel
admin.site.register(Author, AuthorAdmin)

Of course, the above admin class is empty, so the views will remain unchanged for now.

We can also register the models using a decorator on the relevant admin class, like so:

# filename: terminus/catalog/admin.py
 
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
	pass

List view

Customise ModelAdmin class

By default, Django uses a model’s __str__() class to display information on the admin list view. While is is not bad design for smaller projects, once the scale increases it may be necessary to change the display to differentiate records more easily.

For example, let’s say we want to display authors in the list view with entries for Sname, Fname, DOB, DOD:

# filename: terminus/catalog/admin.py
 
class AuthorAdmin(admin.ModelAdmin):
	list_display = ('sname', 'fname', 'date_of_birth', 'date_of_death')

Dealing with ManyToManyFields

Continuing with Terminus Library, if we want a book in the list view to show its title, author, and genre, we might register an admin class like so:

class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'author', 'display_genre')

The display_genre is a method we add into the Book model. In other words, we can use a method’s name here to display it in the list view. Generally we may want to avoid having Django make costly database calls once the DB grows to a certain size.

To make the above work, the Book model must be changed to include the following method:

# filename: terminus/catalog/admin.py
 
class Book(models.Model):
	...
	...
	def display_genre(self):
		"""Create a string for the Genre, used to display genre in Admin"""
		return ', '.join(genre.name for genre in self.genre.all()[:3])
 
	display_genre.short_description = "Genre"

Adding list filters

As the list of items in the admin page grows, it can be useful to create filters. This is done by listing fields in the ModelAdmin list_filter attribute. For instance:

#filename: terminus/catalog/admin.py
class BookInstanceAdmin(admin.ModelAdmin):
	list_filter = ('status', 'due_back')

Detail view

Organizing detail view layout

By default, the detail views lay out the fields vertically in the order that they were declared in a model. To do this, we simply add a fields list attribute to the relevant model:

# filename: terminus/catalog/admin.py
 
class AuthorAdmin(admin.ModelAdmin):
	...
	...
	fields = ['fname', 'sname', ('date_of_birth', 'date_of_death')]

The fields attribute simply declares in what order the fields will be shown on the detail view. Fields are displayed vertically by default, one after the other; however, we can use tuples to show them horizontally.

We can also include an exclude attribute to specify which model attributes to hide.

Sectioning detail view

In the detail view, in addition to organizing the field display orders, we can create sections to group related model information using fieldsets.

For example, if we want to create a section for the BookInstance model that refers to book-specific attributes and another that refers to availability, we might do the following:

# filename: terminus/catalog/admin.py
 
class BookInstanceAdmin(admin.ModelAdmin):
	...
	...
	fieldsets = (
		(None, { # The first item of the tuple is the name of the section
			'fields':('book','imprint','id')
		}),
		('Availability', {
			'fields':('status','due_back')
		})
	)

Inline editing of associated records

If we want the ability to add associated records at the same time, we can use inline editing. This may be useful, for example, if we want to add information about both a book and about a specific copy of a book.

This is achieved by using inline classes, of type TabularInline for horizontal layouts or StackedInline for vertical layouts.

For instance:

# filename: terminus/catalog/admin.py
 
class BooksInstanceInline(admin.TabularInline):
	model = BookInstance
 
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
	...
	...
	inlines = [BookInstanceInline]
 
## Ref
[Django Admin Site](https://docs.djangoproject.com/en/3.1/ref/contrib/admin/)