django-dev-unfold
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUnfold Admin Development
Unfold Admin 开发
Django Unfold admin patterns with modern UI and HTMX customization.
基于Django Unfold的Admin开发模式,包含现代UI与HTMX自定义功能。
Core Principles
核心原则
- One admin = one file - Each ModelAdmin in its own file
- Unfold base classes - Extend UnfoldAdmin classes
- HTMX for dynamics - Use HTMX for interactive features
- Dashboard first - Custom dashboards for data visualization
- Tailwind styling - Consistent Tailwind CSS classes
- 一个Admin对应一个文件 - 每个ModelAdmin单独存放在一个文件中
- Unfold基类 - 继承UnfoldAdmin类
- 用HTMX实现动态效果 - 使用HTMX开发交互式功能
- 仪表盘优先 - 自定义仪表盘用于数据可视化
- Tailwind样式 - 使用统一的Tailwind CSS类
Installation
安装
bash
pip install django-unfoldbash
pip install django-unfoldConfiguration
配置
python
undefinedpython
undefinedconfig/settings.py (with Dynaconf)
config/settings.py(使用Dynaconf)
INSTALLED_APPS = [
"unfold",
"unfold.contrib.filters",
"unfold.contrib.forms",
"unfold.contrib.inlines",
"unfold.contrib.import_export", # Optional
"django.contrib.admin",
# ... other apps
]
INSTALLED_APPS = [
"unfold",
"unfold.contrib.filters",
"unfold.contrib.forms",
"unfold.contrib.inlines",
"unfold.contrib.import_export", # 可选
"django.contrib.admin",
# ... 其他应用
]
Unfold configuration
Unfold 配置
UNFOLD = {
"SITE_TITLE": "My Admin",
"SITE_HEADER": "My Admin",
"SITE_URL": "/",
"SITE_SYMBOL": "speed", # Material Symbols icon
"SHOW_HISTORY": True,
"SHOW_VIEW_ON_SITE": True,
"ENVIRONMENT": "config.settings.environment_callback",
"COLORS": {
"primary": {
"50": "250 245 255",
"100": "243 232 255",
"200": "233 213 255",
"300": "216 180 254",
"400": "192 132 252",
"500": "168 85 247",
"600": "147 51 234",
"700": "126 34 206",
"800": "107 33 168",
"900": "88 28 135",
"950": "59 7 100",
},
},
"SIDEBAR": {
"show_search": True,
"show_all_applications": True,
"navigation": [
{
"title": "Navigation",
"items": [
{
"title": "Dashboard",
"icon": "dashboard",
"link": reverse_lazy("admin:index"),
},
{
"title": "Users",
"icon": "people",
"link": reverse_lazy("admin:users_user_changelist"),
},
],
},
],
},
}
def environment_callback(request):
"""Show environment badge in admin."""
from config.settings import settings
env = settings.current_env
if env == "production":
return ["Production", "danger"]
elif env == "staging":
return ["Staging", "warning"]
return ["Development", "info"]
undefinedUNFOLD = {
"SITE_TITLE": "My Admin",
"SITE_HEADER": "My Admin",
"SITE_URL": "/",
"SITE_SYMBOL": "speed", # Material Symbols 图标
"SHOW_HISTORY": True,
"SHOW_VIEW_ON_SITE": True,
"ENVIRONMENT": "config.settings.environment_callback",
"COLORS": {
"primary": {
"50": "250 245 255",
"100": "243 232 255",
"200": "233 213 255",
"300": "216 180 254",
"400": "192 132 252",
"500": "168 85 247",
"600": "147 51 234",
"700": "126 34 206",
"800": "107 33 168",
"900": "88 28 135",
"950": "59 7 100",
},
},
"SIDEBAR": {
"show_search": True,
"show_all_applications": True,
"navigation": [
{
"title": "导航",
"items": [
{
"title": "仪表盘",
"icon": "dashboard",
"link": reverse_lazy("admin:index"),
},
{
"title": "用户",
"icon": "people",
"link": reverse_lazy("admin:users_user_changelist"),
},
],
},
],
},
}
def environment_callback(request):
"""在Admin中显示环境标识。"""
from config.settings import settings
env = settings.current_env
if env == "production":
return ["Production", "danger"]
elif env == "staging":
return ["Staging", "warning"]
return ["Development", "info"]
undefinedAdmin Structure
Admin 结构
myapp/
└── admin/
├── __init__.py # Register all admins
├── base.py # Base admin classes
├── user.py # UserAdmin
├── product.py # ProductAdmin
└── order.py # OrderAdminmyapp/
└── admin/
├── __init__.py # 注册所有Admin
├── base.py # 基础Admin类
├── user.py # UserAdmin
├── product.py # ProductAdmin
└── order.py # OrderAdminBase Admin Classes
基础Admin类
In :
admin/base.pypython
from django.contrib import admin
from unfold.admin import ModelAdmin
class BaseModelAdmin(ModelAdmin):
"""Base admin with common configuration."""
list_per_page = 25
show_full_result_count = False
# Unfold features
compressed_fields = True
warn_unsaved_form = True
def get_queryset(self, request):
"""Exclude soft-deleted by default."""
qs = super().get_queryset(request)
if hasattr(self.model, "deleted_at"):
qs = qs.filter(deleted_at__isnull=True)
return qs
class ReadOnlyModelAdmin(BaseModelAdmin):
"""Admin for read-only models."""
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False在中:
admin/base.pypython
from django.contrib import admin
from unfold.admin import ModelAdmin
class BaseModelAdmin(ModelAdmin):
"""包含通用配置的基础Admin类。"""
list_per_page = 25
show_full_result_count = False
# Unfold 功能
compressed_fields = True
warn_unsaved_form = True
def get_queryset(self, request):
"""默认排除软删除的数据。"""
qs = super().get_queryset(request)
if hasattr(self.model, "deleted_at"):
qs = qs.filter(deleted_at__isnull=True)
return qs
class ReadOnlyModelAdmin(BaseModelAdmin):
"""用于只读模型的Admin类。"""
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return FalseModelAdmin Template
ModelAdmin 模板
Each admin in its own file ():
admin/user.pypython
from django.contrib import admin
from django.utils.html import format_html
from unfold.admin import ModelAdmin
from unfold.decorators import display
from ..models import User
from .base import BaseModelAdmin
@admin.register(User)
class UserAdmin(BaseModelAdmin):
list_display = ["email", "name", "display_status", "created_at"]
list_filter = ["is_active", "created_at"]
search_fields = ["email", "name"]
ordering = ["-created_at"]
readonly_fields = ["id", "created_at", "updated_at"]
fieldsets = [
(None, {
"fields": ["id", "email", "name"],
}),
("Status", {
"fields": ["is_active"],
"classes": ["collapse"],
}),
("Timestamps", {
"fields": ["created_at", "updated_at"],
"classes": ["collapse"],
}),
]
@display(
description="Status",
label={
True: "success",
False: "danger",
},
)
def display_status(self, obj):
return obj.is_active每个Admin单独存放在一个文件中(如):
admin/user.pypython
from django.contrib import admin
from django.utils.html import format_html
from unfold.admin import ModelAdmin
from unfold.decorators import display
from ..models import User
from .base import BaseModelAdmin
@admin.register(User)
class UserAdmin(BaseModelAdmin):
list_display = ["email", "name", "display_status", "created_at"]
list_filter = ["is_active", "created_at"]
search_fields = ["email", "name"]
ordering = ["-created_at"]
readonly_fields = ["id", "created_at", "updated_at"]
fieldsets = [
(None, {
"fields": ["id", "email", "name"],
}),
("状态", {
"fields": ["is_active"],
"classes": ["collapse"],
}),
("时间戳", {
"fields": ["created_at", "updated_at"],
"classes": ["collapse"],
}),
]
@display(
description="状态",
label={
True: "success",
False: "danger",
},
)
def display_status(self, obj):
return obj.is_activeAdmin Init
Admin 注册初始化
Register all admins in :
admin/__init__.pypython
from .user import UserAdmin
from .product import ProductAdmin
from .order import OrderAdmin
__all__ = [
"UserAdmin",
"ProductAdmin",
"OrderAdmin",
]在中注册所有Admin:
admin/__init__.pypython
from .user import UserAdmin
from .product import ProductAdmin
from .order import OrderAdmin
__all__ = [
"UserAdmin",
"ProductAdmin",
"OrderAdmin",
]Display Decorators
显示装饰器
Unfold provides display decorators for styled output:
python
from unfold.decorators import display
@display(
description="Status",
label={
"active": "success",
"pending": "warning",
"cancelled": "danger",
},
)
def display_status(self, obj):
return obj.status
@display(
description="Amount",
ordering="total_amount",
)
def display_amount(self, obj):
return f"${obj.total_amount:,.2f}"
@display(
description="Actions",
header=True, # Show in header row
)
def display_actions(self, obj):
return format_html(
'<a href="{}" class="btn btn-sm btn-primary">View</a>',
obj.get_absolute_url(),
)Unfold提供用于样式化输出的显示装饰器:
python
from unfold.decorators import display
@display(
description="状态",
label={
"active": "success",
"pending": "warning",
"cancelled": "danger",
},
)
def display_status(self, obj):
return obj.status
@display(
description="金额",
ordering="total_amount",
)
def display_amount(self, obj):
return f"${obj.total_amount:,.2f}"
@display(
description="操作",
header=True, # 在表头行显示
)
def display_actions(self, obj):
return format_html(
'<a href="{}" class="btn btn-sm btn-primary">查看</a>',
obj.get_absolute_url(),
)Filters
过滤器
Unfold filter types:
python
from unfold.contrib.filters.admin import (
RangeDateFilter,
RangeDateTimeFilter,
SingleNumericFilter,
RangeNumericFilter,
SliderNumericFilter,
DropdownFilter,
ChoicesDropdownFilter,
RelatedDropdownFilter,
AutocompleteSelectFilter,
)
@admin.register(Order)
class OrderAdmin(BaseModelAdmin):
list_filter = [
("created_at", RangeDateFilter),
("total_amount", RangeNumericFilter),
("status", ChoicesDropdownFilter),
("user", RelatedDropdownFilter),
]Unfold支持的过滤器类型:
python
from unfold.contrib.filters.admin import (
RangeDateFilter,
RangeDateTimeFilter,
SingleNumericFilter,
RangeNumericFilter,
SliderNumericFilter,
DropdownFilter,
ChoicesDropdownFilter,
RelatedDropdownFilter,
AutocompleteSelectFilter,
)
@admin.register(Order)
class OrderAdmin(BaseModelAdmin):
list_filter = [
("created_at", RangeDateFilter),
("total_amount", RangeNumericFilter),
("status", ChoicesDropdownFilter),
("user", RelatedDropdownFilter),
]Inline Admin
内联Admin
python
from unfold.admin import TabularInline, StackedInline
class OrderItemInline(TabularInline):
model = OrderItem
extra = 0
readonly_fields = ["subtotal"]
def subtotal(self, obj):
return obj.quantity * obj.unit_price
@admin.register(Order)
class OrderAdmin(BaseModelAdmin):
inlines = [OrderItemInline]python
from unfold.admin import TabularInline, StackedInline
class OrderItemInline(TabularInline):
model = OrderItem
extra = 0
readonly_fields = ["subtotal"]
def subtotal(self, obj):
return obj.quantity * obj.unit_price
@admin.register(Order)
class OrderAdmin(BaseModelAdmin):
inlines = [OrderItemInline]HTMX Actions
HTMX 操作
See for HTMX patterns including:
references/customization.md- Dynamic field updates
- Inline actions
- Modal dialogs
- Live search
详见中的HTMX模式,包括:
references/customization.md- 动态字段更新
- 内联操作
- 模态对话框
- 实时搜索
Dashboard
仪表盘
Custom dashboard in . See .
admin/dashboard.pyreferences/customization.md在中自定义仪表盘。详见。
admin/dashboard.pyreferences/customization.mdAdditional Resources
其他资源
Reference Files
参考文件
- - HTMX patterns, dashboard setup, custom widgets
references/customization.md
- - HTMX模式、仪表盘设置、自定义组件
references/customization.md
Related Skills
相关技能
- django-dev - Core Django patterns
- django-dev-test - Testing admin functionality
- django-dev - 核心Django开发模式
- django-dev-test - Admin功能测试