unfold-admin について
unfold-admin は、Django の管理画面を構築・カスタマイズする開発者向けのテーマです。ModelAdmin を拡張し、フィルター、フォームウィジェット、インライン編集、ダッシュボードコンポーネントを提供します。
主な機能
- 01サイトのブランディングとサイドバー設定
- 02リスト操作と表示列の拡張
- 03高度なフィルターとフォームウィジェット
- 04ページネーション・並べ替え対応のタブ付きインライン
- 05ダッシュボードカードとデータパネル
活用シーン
- 01Django モデルの管理ページ設定
- 02リストへのフィルターと一括操作の追加
- 03関連データのタブ式編集画面の構築
- 04管理ダッシュボードでの KPI カード表示
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ 0xdarkmatter/ claude-mods --skill unfold-adminインストール後、Claude Code で/unfold-adminを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/actions-filters.mdconfiguration.mddashboard.mdresources.mdwidgets-inlines.md詳細
Django Unfold 管理画面
Tailwind CSS、HTMX、Alpine.js を使用したモダンな Django 管理画面テーマです。Django のデフォルト管理画面を、洗練された機能豊富なインターフェースに置き換えます。
クイックスタート
インストール
# settings.py - unfold MUST be before django.contrib.admin
INSTALLED_APPS = [
"unfold",
"unfold.contrib.filters", # advanced filters
"unfold.contrib.forms", # array/wysiwyg widgets
"unfold.contrib.inlines", # nonrelated inlines
"unfold.contrib.import_export", # styled import/export
"unfold.contrib.guardian", # django-guardian integration
"unfold.contrib.simple_history", # django-simple-history integration
"unfold.contrib.constance", # django-constance integration
"unfold.contrib.location_field", # django-location-field integration
# ...
"django.contrib.admin",
]
最小限の管理画面
from unfold.admin import ModelAdmin
@admin.register(MyModel)
class MyModelAdmin(ModelAdmin):
pass # inherits Unfold styling
サイトの設定
デフォルトの AdminSite を置き換えるか、設定内の UNFOLD 辞書で設定します。設定の詳細については、references/configuration.md を参照してください。
UNFOLD = {
"SITE_TITLE": "My Admin",
"SITE_HEADER": "My Admin",
"SITE_SYMBOL": "dashboard", # Material Symbols icon name
"SIDEBAR": {
"show_search": True,
"navigation": [
{
"title": _("Navigation"),
"items": [
{
"title": _("Dashboard"),
"icon": "dashboard",
"link": reverse_lazy("admin:index"),
},
],
},
],
},
}
基本的なワークフロー
Unfold の管理画面インターフェースを構築する際は、次の手順に従ってください。
- サイトを設定する - UNFOLD 設定辞書(ブランディング、サイドバー、テーマ)
- モデルを登録する -
unfold.admin.ModelAdminを拡張します - 表示を拡張する - リスト列に
@displayデコレーターを使用します - アクションを追加する - 行/リスト/詳細/送信アクションに
@actionデコレーターを使用します - フィルターを設定する - デフォルトのフィルターを Unfold のフィルタークラスに置き換えます
- ウィジェットをオーバーライドする -
formfield_overridesで Unfold のウィジェットを適用します - インラインを設定する - タブ、ページネーション、並べ替えに対応した Unfold のインラインクラスを使用します
- ダッシュボードを構築する - KPI カードに
@register_componentとBaseComponentを使用します
ModelAdmin の属性
Unfold は Django の ModelAdmin を拡張し、次の属性を追加します。
| 属性 | 型 | 用途 |
|---|---|---|
list_fullwidth | bool | 全幅の変更一覧(サイドバーなし) |
list_filter_submit | bool | フィルターに送信ボタンを追加 |
list_filter_sheet | bool | スライド式シートパネルにフィルターを表示 |
compressed_fields | bool | フォームのフィールド間隔を詰める |
warn_unsaved_form | bool | 保存されていないフォームから移動する前に警告 |
ordering_field | str | ドラッグで並べ替えるフィールド名 |
hide_ordering_field | bool | 並べ替えフィールドの列を非表示にする |
list_horizontal_scrollbar_top | bool | リストの上部にスクロールバーを表示 |
list_disable_select_all | bool | 「すべて選択」チェックボックスを無効にする |
change_form_show_cancel_button | bool | フォームにキャンセルボタンを表示 |
actions_list | list | 変更一覧のグローバルアクション |
actions_row | list | 変更一覧の行ごとのアクション |
actions_detail | list | 変更フォームのアクション |
actions_submit_line | list | フォーム送信エリアのアクション |
actions_list_hide_default | bool | デフォルトのリストアクションを非表示にする |
actions_detail_hide_default | bool | デフォルトの詳細アクションを非表示にする |
conditional_fields | dict | フィールドの表示を制御する JS 式 |
change_form_datasets | list | 変更フォーム用の BaseDataset サブクラス |
list_sections | list | リスト用の TableSection/TemplateSection |
list_sections_classes | str | セクション用の CSS グリッドクラス |
readonly_preprocess_fields | dict | 読み取り専用フィールドの内容を変換 |
add_fieldsets | list | 追加フォーム用の個別フィールドセット(UserAdmin のような形式) |
テンプレートの挿入ポイント
変更一覧または変更フォームの前後にカスタム HTML を挿入します。
class MyAdmin(ModelAdmin):
# Changelist
list_before_template = "myapp/list_before.html"
list_after_template = "myapp/list_after.html"
# Change form (inside <form> tag)
change_form_before_template = "myapp/form_before.html"
change_form_after_template = "myapp/form_after.html"
# Change form (outside <form> tag)
change_form_outer_before_template = "myapp/outer_before.html"
change_form_outer_after_template = "myapp/outer_after.html"
条件付きフィールド
他のフィールドの値に基づいてフィールドを表示/非表示にします(Alpine.js 式)。
class MyAdmin(ModelAdmin):
conditional_fields = {
"premium_features": "plan == 'PRO'",
"discount_amount": "has_discount == true",
}
アクションシステム
アクションには、シグネチャがそれぞれ異なる 4 種類があります。詳細については、references/actions-filters.md を参照してください。
from unfold.decorators import action
from unfold.enums import ActionVariant
# List action (no object context)
@action(description=_("Rebuild Index"), icon="sync", variant=ActionVariant.PRIMARY)
def rebuild_index(self, request):
# process...
return redirect(request.headers["referer"])
# Row action (receives object_id)
@action(description=_("Approve"), url_path="approve")
def approve_row(self, request, object_id):
obj = self.model.objects.get(pk=object_id)
return redirect(request.headers["referer"])
# Detail action (receives object_id, shown on change form)
@action(description=_("Send Email"), permissions=["send_email"])
def send_email(self, request, object_id):
return redirect(reverse_lazy("admin:myapp_mymodel_change", args=[object_id]))
# Submit line action (receives obj instance, runs on save)
@action(description=_("Save & Publish"))
def save_and_publish(self, request, obj):
obj.published = True
アクショングループ(ドロップダウンメニュー)
actions_list = [
"primary_action",
{
"title": _("More"),
"variant": ActionVariant.PRIMARY,
"items": ["secondary_action", "tertiary_action"],
},
]
権限
@action(permissions=["can_export", "auth.view_user"])
def export_data(self, request):
pass
def has_can_export_permission(self, request):
return request.user.is_superuser
Display デコレーター
list_display の列を拡張します。references/actions-filters.md を参照してください。
from unfold.decorators import display
# Colored status labels
@display(description=_("Status"), ordering="status", label={
"active": "success", # green
"pending": "info", # blue
"warning": "warning", # orange
"inactive": "danger", # red
})
def show_status(self, obj):
return obj.status
# Rich header with avatar
@display(description=_("User"), header=True)
def show_header(self, obj):
return [
obj.full_name, # primary text
obj.email, # secondary text
obj.initials, # badge text
{"path": obj.avatar.url, "width": 24, "height": 24, "borderless": True},
]
# Interactive dropdown
@display(description=_("Teams"), dropdown=True)
def show_teams(self, obj):
return {
"title": f"{obj.teams.count()} teams",
"items": [{"title": t.name, "link": t.get_admin_url()} for t in obj.teams.all()],
"striped": True,
"max_height": 200,
}
# Boolean checkmark
@display(description=_("Active"), boolean=True)
def is_active(self, obj):
return obj.is_active
フィルター
Unfold は高度なフィルタークラスを提供します。references/actions-filters.md を参照してください。
from unfold.contrib.filters.admin import (
TextFilter, RangeNumericFilter, RangeDateFilter, RangeDateTimeFilter,
SingleNumericFilter, SliderNumericFilter, RelatedDropdownFilter,
RelatedCheckboxFilter, ChoicesCheckboxFilter, AllValuesCheckboxFilter,
BooleanRadioFilter, CheckboxFilter, AutocompleteSelectMultipleFilter,
)
class MyAdmin(ModelAdmin):
list_filter_submit = True # required for input-based filters
list_filter = [
("salary", RangeNumericFilter),
("status", ChoicesCheckboxFilter),
("created_at", RangeDateFilter),
("category", RelatedDropdownFilter),
("is_active", BooleanRadioFilter),
]
カスタムテキストフィルター
class NameFilter(TextFilter):
title = _("Name")
parameter_name = "name"
def queryset(self, request, queryset):
if self.value() in EMPTY_VALUES:
return queryset
return queryset.filter(name__icontains=self.value())
ウィジェット
Unfold のスタイルを適用するために、フォームウィジェットをオーバーライドします。references/widgets-inlines.md を参照してください。
from unfold.widgets import (
UnfoldAdminTextInputWidget, UnfoldAdminSelectWidget, UnfoldAdminSelect2Widget,
UnfoldBooleanSwitchWidget, UnfoldAdminColorInputWidget,
UnfoldAdminSplitDateTimeWidget, UnfoldAdminImageFieldWidget,
)
from unfold.contrib.forms.widgets import WysiwygWidget, ArrayWidget
class MyAdmin(ModelAdmin):
formfield_overrides = {
models.TextField: {"widget": WysiwygWidget},
models.ImageField: {"widget": UnfoldAdminImageFieldWidget},
}
アイコン付きテキスト入力
widget = UnfoldAdminTextInputWidget(attrs={
"prefix_icon": "search",
"suffix_icon": "euro",
})
インライン
Unfold のインラインは、タブ、ページネーション、並べ替え、非関連モデルに対応しています。references/widgets-inlines.md を参照してください。
from unfold.admin import TabularInline, StackedInline
from unfold.contrib.inlines.admin import NonrelatedStackedInline
class OrderItemInline(TabularInline):
model = OrderItem
tab = True # show as tab
per_page = 10 # paginated
ordering_field = "weight" # drag-to-reorder
hide_title = True
collapsible = True
フィールドセットのタブ
"classes": ["tab"] を使って、フィールドセットをタブにまとめます。
fieldsets = [
(None, {"fields": ["name", "email"]}), # always visible
(_("Profile"), {"classes": ["tab"], "fields": ["bio", "avatar"]}),
(_("Settings"), {"classes": ["tab"], "fields": ["theme", "notifications"]}),
]
ダッシュボードコンポーネント
KPI カードやカスタムダッシュボードウィジェットを作成します。詳しくは references/dashboard.md を参照してください。
from unfold.components import BaseComponent, register_component
from django.template.loader import render_to_string
@register_component
class ActiveUsersComponent(BaseComponent):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["children"] = render_to_string("myapp/kpi_card.html", {
"total": User.objects.filter(is_active=True).count(),
"label": "Active Users",
})
return context
設定で構成します:
UNFOLD = {
"DASHBOARD_CALLBACK": "myapp.views.dashboard_callback",
}
セクション(変更一覧パネル)
関連データのパネルを変更一覧ビューに埋め込みます:
from unfold.sections import TableSection, TemplateSection
class RecentOrdersSection(TableSection):
related_name = "order_set"
fields = ["id", "total", "status"]
height = 380
class ChartSection(TemplateSection):
template_name = "myapp/chart.html"
class MyAdmin(ModelAdmin):
list_sections = [RecentOrdersSection, ChartSection]
list_sections_classes = "lg:grid-cols-2"
データセット(変更フォームパネル)
モデルの一覧を変更フォーム内に埋め込みます:
from unfold.datasets import BaseDataset
class RelatedItemsDatasetAdmin(ModelAdmin):
list_display = ["name", "status"]
search_fields = ["name"]
class RelatedItemsDataset(BaseDataset):
model = RelatedItem
model_admin = RelatedItemsDatasetAdmin
tab = True # show as tab
class MyAdmin(ModelAdmin):
change_form_datasets = [RelatedItemsDataset]
ページネーター
無限スクロールのページネーションを使用します:
from unfold.paginator import InfinitePaginator
class MyAdmin(ModelAdmin):
paginator = InfinitePaginator
show_full_result_count = False
list_per_page = 20
サードパーティ連携
Unfold は、一般的な Django パッケージ向けにスタイルを適用したラッパーを提供します。詳しいセットアップガイドは references/resources.md を参照してください。
| パッケージ | Unfold モジュール | セットアップ |
|---|---|---|
| django-import-export | unfold.contrib.import_export | ImportForm、ExportForm、SelectableFieldsExportForm を使用します |
| django-guardian | unfold.contrib.guardian | スタイルを適用した guardian 連携 |
| django-simple-history | unfold.contrib.simple_history | スタイルを適用した履歴連携 |
| django-constance | unfold.contrib.constance | スタイルを適用した constance 設定 |
| django-location-field | unfold.contrib.location_field | 位置情報ウィジェット |
| django-modeltranslation | 対応 | TabbedTranslationAdmin と ModelAdmin を組み合わせます |
| django-celery-beat | 対応(再配線) | 5 つのモデルの登録を解除し、Unfold で再登録します |
| django-money | unfold.widgets | UnfoldAdminMoneyWidget |
| djangoql | 対応 | DjangoQLSearchMixin と ModelAdmin を組み合わせます |
| django-crispy-forms | 対応 | Unfold テンプレートパックを利用できます |
# Multiple inheritance - Unfold ModelAdmin always last
@admin.register(MyModel)
class MyAdmin(DjangoQLSearchMixin, SimpleHistoryAdmin, GuardedModelAdmin, ModelAdmin):
pass
組み込みテンプレートコンポーネント
Unfold には、ダッシュボードやカスタムページで再利用できるテンプレートコンポーネントが含まれています:
| コンポーネント | パス | 主な変数 |
|---|---|---|
| カード | unfold/components/card.html | title、footer、label、icon |
| 棒グラフ | unfold/components/chart/bar.html | data(JSON)、height、width |
| 折れ線グラフ | unfold/components/chart/line.html | data(JSON)、height、width |
| 進捗状況 | unfold/components/progress.html | value、title、description |
| テーブル | unfold/components/table.html | table、card_included、striped |
| ボタン | unfold/components/button.html | name、href、submit |
| トラッカー | unfold/components/tracker.html | data |
| コホート | unfold/components/cohort.html | data |
{% load unfold %}
{% component "MyKPIComponent" %}{% endcomponent %}
ユーザー管理フォーム
Unfold は、Django の認証管理フォームにスタイルを適用したバージョンを提供します:
from unfold.forms import AdminPasswordChangeForm, UserChangeForm, UserCreationForm
@admin.register(User)
class UserAdmin(BaseUserAdmin, ModelAdmin):
form = UserChangeForm
add_form = UserCreationForm
change_password_form = AdminPasswordChangeForm
リファレンスファイル
トピックごとに分けた詳細ドキュメント:
- references/configuration.md - UNFOLD 設定辞書全般、サイドバー、タブ、テーマ設定、環境、ログイン
- references/actions-filters.md - アクションの種類とシグネチャ、表示デコレーター、すべてのフィルタークラス
- references/widgets-inlines.md - ウィジェットクラス一覧(35 種以上)、インラインのバリエーション、非関連インライン、フォーム
- references/dashboard.md - ダッシュボードコンポーネント、セクション、データセット、カスタムテンプレート、Tailwind のパターン
- references/resources.md - 公式リンク、すべてのサードパーティ連携、一般的なパターン、バージョン互換性、Unfold Studio
詳細な設定オプション、利用可能なクラスの全一覧、コード例の全容、または特定の機能領域の連携セットアップガイドが必要な場合は、該当するリファレンスファイルを参照してください。
主な外部リファレンス
| リソース | URL |
|---|---|
| ドキュメント | https://unfoldadmin.com/docs/ |
| GitHub | https://github.com/unfoldadmin/django-unfold |
| デモアプリ(Formula) | https://github.com/unfoldadmin/formula |
| ライブデモ | https://demo.unfoldadmin.com |
| Material Symbols(アイコン) | https://fonts.google.com/icons |
実装パターンが不明な場合は、Formula デモリポジトリの formula/admin.py と formula/settings.py を参照してください。Unfold のほぼすべての機能が網羅されています。