Unfold implements special functionality for handling expandable rows in changelists called sections. Once the list_sections attribute is configured, rows in the changelist will display an arrow button at the beginning of the row which can be used to show additional content.
The list_sections attribute consists of Python classes inheriting from TableSection or TemplateSection defined in unfold.sections. These classes are responsible for rendering the content in the expandable area.
from unfold.admin import ModelAdmin
from unfold.sections import TableSection, TemplateSection
from .models import SomeModel
# Table for related records
class CustomTableSection(TableSection):
verbose_name = _("Table title") # Displays custom table title
height = 300 # Force the table height. Ideal for large amount of records
related_name = "related_name_set" # Related model field name
fields = ["pk", "title", "custom_field"] # Fields from related model
# Custom field
def custom_field(self, instance):
return instance.pk
# Simple template with custom content
class CardSection(TemplateSection):
template_name = "your_app/some_template.html"
@admin.register(SomeModel)
class SomeAdmin(ModelAdmin):
list_sections = [
CardSection,
CustomTableSection,
]
When it comes to classes inheriting from TableSection, you may find a problem with an extraordinary amount of queries executed on changelist pages. This problem has two parts:
TableSection works with related fields so another query is required to obtain data from the related tableThe easiest solution for this issue is to configure pagination to a smaller amount of records by setting list_per_page = 20. While this solution might work for you, it is not optimal.
The optimal solution is using prefetch_related:
get_queryset and use prefetch_related on all related rows until you don't have any duplicated SQL queries in django-debug-toolbar outputfrom unfold.admin import ModelAdmin
from .models import SomeModel
@admin.register(SomeModel)
class SomeAdmin(ModelAdmin):
list_per_page = 20 # Quick solution
list_sections = [CustomTableSection]
# Custom queryset prefetching related records
def get_queryset(self, request):
return (
super()
.get_queryset(request)
.prefetch_related(
"related_field_set",
"related_field__another_related_field",
"related_field__another_related_field__even_more_related_field",
)
)
Unfold supports multiple related tables in expandable rows. Specify a section class for each related field and put them into list_sections. For each class, you can add a verbose_name to display a custom title right above the table to distinguish between different related fields.
from unfold.admin import ModelAdmin
from .models import SomeModel
@admin.register(SomeModel)
class SomeAdmin(ModelAdmin):
list_sections = [
CustomTableSection, OtherCustomTable
]
© 2023 - 2025 Created by unfoldadmin.com. All rights reserved.