Overview
The @display decorator enhances Django’s standard @display decorator with Unfold-specific features for customizing list display fields, including labels, headers, and dropdown formatting.
Decorator Signature
from unfold.decorators import display
@display(
function: Callable[[Model], Any] | None = None,
*,
boolean: bool | None = None,
image: bool | None = None,
ordering: str | Combinable | BaseExpression | None = None,
description: str | None = None,
empty_value: str | None = None,
dropdown: bool | None = None,
label: bool | str | dict[str, str] | None = None,
header: bool | None = None,
) -> Callable
Located in unfold/decorators.py:98
Parameters
function
Callable[[Model], Any] | None
default:"None"
The function to decorate. Can be None when using the decorator with parameters.
boolean
bool | None
default:"None"
Display the field as a boolean (True/False icon). Mutually exclusive with empty_value.
image
bool | None
default:"None"
Display the field as an image thumbnail.
ordering
str | Combinable | BaseExpression | None
default:"None"
Field name or expression to use for ordering when clicking the column header.
Column header text. Defaults to the function name.
String to display when the value is empty. Mutually exclusive with boolean.
dropdown
bool | None
default:"None"
Display the field in a dropdown format (Unfold-specific).
label
bool | str | dict[str, str] | None
default:"None"
Display the field as a label/badge with styling. Can be:
True: Auto-detect label style
str: Use specific color (e.g., "success", "warning")
dict: Map values to colors (e.g., {"published": "success", "draft": "warning"})
Display the field as a header with enhanced styling (Unfold-specific).
Usage Examples
Basic Display
from django.contrib import admin
from unfold.admin import ModelAdmin
from unfold.decorators import display
@admin.register(Article)
class ArticleAdmin(ModelAdmin):
list_display = ["title", "author_name", "status"]
@display(description="Author")
def author_name(self, obj):
return obj.author.get_full_name()
Boolean Display
@admin.register(Article)
class ArticleAdmin(ModelAdmin):
list_display = ["title", "is_published", "has_images"]
@display(boolean=True, description="Published")
def is_published(self, obj):
return obj.status == "published"
@display(boolean=True, ordering="images__count")
def has_images(self, obj):
return obj.images.exists()
Image Display
@admin.register(Product)
class ProductAdmin(ModelAdmin):
list_display = ["name", "thumbnail", "price"]
@display(image=True, description="Preview")
def thumbnail(self, obj):
if obj.image:
return obj.image.url
return None
Label Display with Colors
@admin.register(Article)
class ArticleAdmin(ModelAdmin):
list_display = ["title", "status_label", "priority_label"]
@display(
description="Status",
label={
"published": "success",
"draft": "warning",
"archived": "danger",
},
)
def status_label(self, obj):
return obj.status
@display(
description="Priority",
label=True, # Auto-detect color
)
def priority_label(self, obj):
return obj.priority
Label with Single Color
@display(description="Category", label="info")
def category_label(self, obj):
return obj.category.name
Empty Value Handling
@admin.register(Article)
class ArticleAdmin(ModelAdmin):
list_display = ["title", "published_date"]
@display(
description="Published",
empty_value="Not published yet",
ordering="published_at",
)
def published_date(self, obj):
return obj.published_at
Dropdown Display
@admin.register(Article)
class ArticleAdmin(ModelAdmin):
list_display = ["title", "tags_dropdown"]
@display(description="Tags", dropdown=True)
def tags_dropdown(self, obj):
return [tag.name for tag in obj.tags.all()]
@admin.register(Article)
class ArticleAdmin(ModelAdmin):
list_display = ["title_header", "author", "date"]
@display(header=True, description="Article Title")
def title_header(self, obj):
return obj.title
Ordering with Expression
from django.db.models import Count
@admin.register(Author)
class AuthorAdmin(ModelAdmin):
list_display = ["name", "article_count"]
@display(
description="Articles",
ordering=Count("articles"),
)
def article_count(self, obj):
return obj.articles.count()
Complex Display with HTML
from django.utils.html import format_html
@admin.register(Article)
class ArticleAdmin(ModelAdmin):
list_display = ["title", "author_with_link"]
@display(description="Author", ordering="author__last_name")
def author_with_link(self, obj):
url = f"/admin/authors/author/{obj.author.id}/change/"
return format_html(
'<a href="{}">{}</a>',
url,
obj.author.get_full_name()
)
Combining Multiple Options
@display(
description="Verification Status",
label={"verified": "success", "pending": "warning", "rejected": "danger"},
ordering="verified_at",
empty_value="Not verified",
)
def verification_status(self, obj):
if obj.verified_at:
return "verified"
elif obj.rejected_at:
return "rejected"
return "pending"
Label Color Options
When using the label parameter, the following color values are typically supported:
"success" - Green badge
"warning" - Yellow/orange badge
"danger" - Red badge
"info" - Blue badge
"default" - Gray badge
Notes
- The
boolean and empty_value parameters are mutually exclusive. Using both will raise a ValueError.
- When using
boolean=True, the decorator will display checkmark/cross icons instead of text.
- The
image parameter expects the function to return a URL string.
- The
label parameter with a dictionary maps return values to specific colors.
- The
ordering parameter can accept field names, related field lookups, or Django ORM expressions.