Skip to content

Editing Related Records Inline

An animal's page shows us the animal, but not its adoption applications.

Employees who review applications want to see both on one page.

Adding a Tabular Inline

An inline adds the rows of a related model to a model's page. We'll add one for adoption applications. First, import AdoptionApplication at the top of animals/admin.py:

animals/admin.py
from django.contrib import admin

from .models import AdoptionApplication, Animal

Then add the inline, above AnimalAdmin:

animals/admin.py
class AdoptionApplicationInline(admin.TabularInline):
    model = AdoptionApplication
    # extra is how many empty rows the table shows for adding applications.
    # The default is 3. Visitors create applications, so show none.
    extra = 0

TabularInline uses the foreign key to show the related rows as a table. So each animal's page will show the applications for that animal.

Add the AdoptionApplicationInline to the AnimalAdmin:

animals/admin.py
    list_display = ["name", "species", "breed", "status", "intake_date"]
    list_filter = ["species", "status"]
    search_fields = ["name", "breed"]
    inlines = [AdoptionApplicationInline]

Open Pepper. Below the animal's fields is a table of Pepper's applications.

Every field in the table can be edited, which isn't the behavior we want.

A Review Table

When reviewing applications, we need to see who applied and how to reach them, and the only thing we should change in the table is the status:

animals/admin.py
class AdoptionApplicationInline(admin.TabularInline):
    model = AdoptionApplication
    # A review table: who applied, how to reach them, and the status to set.
    fields = ["applicant_name", "email", "status"]
    readonly_fields = ["applicant_name", "email"]
    # extra is how many empty rows the table shows for adding applications.
    # The default is 3. Visitors create applications, so show none.
    extra = 0
  • fields: The table's columns, in order.
  • readonly_fields: Fields shown as text, without an input. A read-only field still has to be in fields to be shown in the table.

Reload Pepper's page. Each applicant's name and email are text now, and the status is the only field you can edit.

Refusing New Rows with has_add_permission()

Visitors create applications, so the table shouldn't add any. extra = 0 shows no empty rows, but the Add another Adoption application link below the table still adds one.

Before saving or displaying, the admin calls methods like has_add_permission(), which return True or False. Add one to the inline:

animals/admin.py
    def has_add_permission(self, request, obj):
        # Applications come from visitors, so the table has no row for adding one.
        return False

obj is the animal whose page this is. With False, the link is gone, and a new row posted anyway isn't saved.