django-unfold-4: @display装饰器
本文描述了在django unfold中使用@display装饰器,在显示列表数据时,给组件提供数据。参考 Django Unfold @display装饰器文档。
Django中的@display装饰器
1. 基本概念
@display装饰器可以应用于模型类的方法,将这些方法作为虚拟字段显示在 Admin 的 list_display中。
python
from django.contrib import admin
from django.contrib.admin.decorators import display
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.IntegerField()
@display(description='库存状态')
def stock_status(self):
if self.stock > 50:
return '充足'
elif self.stock > 10:
return '一般'
else:
return '紧缺'2. 在 Admin 中注册使用
python
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ['name', 'price', 'stock', 'stock_status']3. 主要参数详解
- description: 设置列标题。
- ordering: 排序字段。
- boolean: 是否显示为布尔值。
python
@display(description='价格', ordering='price')
def formatted_price(self):
return f"¥{self.price}"
@display(description='有库存', boolean=True)
def has_stock(self):
return self.stock > 04. 复杂业务逻辑
python
class Order(models.Model):
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
status = models.CharField(max_length=20)
created_at = models.DateTimeField(auto_now_add=True)
@display(description='订单状态')
def order_status_with_color(self):
status_colors = {
'pending': 'orange',
'paid': 'green',
'shipped': 'blue',
'delivered': 'purple'
}
color = status_colors.get(self.status, 'gray')
return format_html(
'<span style="color: {};">{}</span>',
color, self.get_status_display()
)
@display(description='金额范围')
def amount_range(self):
if self.total_amount < 100:
return '小额'
elif self.total_amount < 1000:
return '中额'
else:
return '大额'Django Unfold中的@display装饰器
Unfold 提供了自己增强版的 @display装饰器,它兼容 Django 原生的装饰器,但增加了更强大的自定义功能,主要用于美化和管理后台列表页(changelist)中字段的显示方式。
两种主要增强功能
A. 标签显示
通过 label参数,可以将字段值渲染成一个带有颜色背景的标签(类似徽章),非常适合显示状态等信息。 基本用法 (label=True): 使用默认的颜色方案。 高级用法 (label={值: 颜色}): 自定义不同值对应的颜色。支持的颜色有:
- success(绿色):成功/完成状态
- info(蓝色):信息/中性状态
- warning(橙色):警告状态
- danger(红色):危险/错误状态
B. 双行标题显示
通过 header=True参数,可以在一个表格单元格内显示两行信息,并可选地添加一个头像或图标前缀。 返回值: 需要返回一个包含2个或3个元素的列表/元组。 [第一行主标题, 第二行副标题, (可选) 前缀信息] 前缀信息: 可以是一段文本(如姓名缩写),也可以是一个包含图片路径和样式的字典,用于显示头像。
python
# admin.py
from django.db.models import TextChoices
from django.utils.translation import gettext_lazy as _
from unfold.admin import ModelAdmin
from unfold.decorators import display
class UserStatus(TextChoices):
ACTIVE = "ACTIVE", _("Active")
PENDING = "PENDING", _("Pending")
INACTIVE = "INACTIVE", _("Inactive")
CANCELLED = "CANCELLED", _("Cancelled")
class UserAdmin(ModelAdmin):
list_display = [
"display_as_two_line_heading",
"show_status",
"show_status_with_custom_label",
]
@display(
description=_("Status"),
ordering="status",
label=True
)
def show_status_default_color(self, obj): # 默认颜色
return obj.status
@display(
description=_("Status"),
ordering="status",
label={
UserStatus.ACTIVE: "success", # green
UserStatus.PENDING: "info", # blue
UserStatus.INACTIVE: "warning", # orange
UserStatus.CANCELLED: "danger", # red
},
)
def show_status_customized_color(self, obj): # 自定义颜色
return obj.status
@display(description=_("Status with label"), ordering="status", label=True)
def show_status_with_custom_label(self, obj): # 自定义标签
return obj.status, obj.get_status_display()
@display(header=True) # 双行标题
def display_as_two_line_heading(self, obj):
"""
Third argument is short text which will appear as prefix in circle
"""
return [
"First main heading",
"Smaller additional description", # Use None in case you don't need it
"AB", # Short text which will appear in front of
# Image instead of initials. Initials are ignored if image is available
{
"path": "some/path/picture.jpg",
"squared": True, # Picture is displayed in square format, if empty circle
"borderless": True, # Picture will be displayed without border
"width": 64, # Removes default width. Use together with height
"height": 48, # Removes default height. Use together with width
}
]下拉菜单支持
这是一个非常强大的功能,通过 dropdown=True参数,可以将任何字段变成一个可点击的下拉菜单。 列表式下拉菜单: 提供一个 items列表来生成传统的菜单项列表,每个菜单项可以包含标题和链接。可以自定义菜单的宽度、高度和样式(如条纹间隔)。 参数包括:
- title (required) - The text that appears in the column header and serves as the dropdown trigger
- items (required) - An array of menu items to be displayed in the dropdown. Each item requires:
- title - The text label for the menu item
- link (optional) - A URL or path that the item will link to when clicked
- striped (optional) - When set to true, adds alternating background colors to list items for better visual separation
- height (optional) - Sets a maximum height in pixels, after which the content becomes scrollable
- width (optional) - Defines the dropdown's width in pixels for precise layout control
python
class UserAdmin(ModelAdmin):
list_display = [
"display_dropdown",
]
@display(description=_("Status"), dropdown=True)
def display_dropdown(self, obj):
return {
# Clickable title displayed in the column
"title": "Custom dropdown title",
# Striped design for the items
"striped": True, # Optional
# Dropdown height. Will display scrollbar for longer content
"height": 200, # Optional
# Dropdown width
"width": 240, # Optional
"items": [
{
"title": "First title",
"link": "#" # Optional
},
{
"title": "Second title",
"link": "#" # Optional
},
]
}自定义模板下拉菜单: 通过 content参数,可以注入任何自定义的 HTML 模板内容,从而实现高度复杂和交互式的下拉界面(例如,内嵌图表、表单等)。
python
class UserAdmin(ModelAdmin):
list_display = [
"display_dropdown",
]
@display(description=_("Status"), dropdown=True)
def display_dropdown(self, obj):
return {
"title": "Custom dropdown title",
"content": "template content",
}使用技巧
- 性能考虑:避免在 @display方法中进行复杂的数据库查询
- HTML 安全:使用 format_html()确保 HTML 内容安全
- 翻译支持:对描述文本使用 gettext_lazy
python
from django.utils.translation import gettext_lazy as _
@display(description=_('Product Status'))
def status_display(self):
return self.get_status_display()