Skip to content

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 > 0

4. 复杂业务逻辑

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",
        }

使用技巧

  1. 性能考虑:避免在 @display方法中进行复杂的数据库查询
  2. HTML 安全:使用 format_html()确保 HTML 内容安全
  3. 翻译支持:对描述文本使用 gettext_lazy
python
from django.utils.translation import gettext_lazy as _

@display(description=_('Product Status'))
def status_display(self):
    return self.get_status_display()

Released under the Apache 2.0 License.