You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Admin-UnFold:如何在AAA列表页预览关联BBB的次级表格

在Django Admin-UnFold的AAA列表页实现关联BBB的预览表格

完全可以实现这个需求,核心思路是给AAA的列表页新增预览按钮列,点击后通过GET参数传递选中的AAA ID,再在列表页下方渲染对应的BBB关联数据表格。以下是适配UnFold框架的具体实现步骤:

1. 基础模型与Admin配置假设

先确认你的基础模型结构(如果已有可跳过):

# models.py
from django.db import models

class AAA(models.Model):
    name = models.CharField(max_length=100, verbose_name="AAA名称")
    # 其他业务字段

class BBB(models.Model):
    aaa = models.ForeignKey(AAA, on_delete=models.CASCADE, related_name="bbbs", verbose_name="关联AAA")
    title = models.CharField(max_length=100, verbose_name="BBB标题")
    # 其他业务字段

2. 自定义AAA Admin类

给AAA的Admin添加预览按钮列,并处理请求参数传递的选中AAA ID,获取对应的BBB数据:

# admin.py
from django.contrib import admin
from django.utils.html import format_html
from django.http import JsonResponse
from unfold.admin import ModelAdmin
from .models import AAA, BBB

class AAAAdmin(ModelAdmin):
    # 列表页显示字段,新增预览按钮列
    list_display = ("name", "preview_bbb")

    def preview_bbb(self, obj):
        # 生成适配UnFold风格的预览按钮,带AAA ID参数
        return format_html(
            '<a href="?aaa_id={}" class="button button-small">预览BBB</a>',
            obj.id
        )
    preview_bbb.short_description = "关联BBB预览"

    def changelist_view(self, request, extra_context=None):
        extra_context = extra_context or {}
        selected_aaa_id = request.GET.get("aaa_id")

        if selected_aaa_id:
            selected_aaa = AAA.objects.get(id=selected_aaa_id)
            # 获取当前AAA关联的所有BBB
            bbb_queryset = BBB.objects.filter(aaa_id=selected_aaa_id)

            # 处理AJAX请求(可选,实现无刷新加载)
            if request.GET.get("ajax") == "1":
                bbb_data = list(bbb_queryset.values("id", "title"))
                return JsonResponse({
                    "aaa_name": selected_aaa.name,
                    "bbb_list": bbb_data
                })

            # 非AJAX请求,传递数据到模板
            extra_context.update({
                "selected_aaa": selected_aaa,
                "bbb_list": bbb_queryset,
                "selected_aaa_id": selected_aaa_id
            })

        return super().changelist_view(request, extra_context=extra_context)

admin.site.register(AAA, AAAAdmin)
admin.site.register(BBB)

3. 自定义AAA列表页模板

继承UnFold的列表页模板,在原有表格下方添加BBB预览表格区域。创建模板文件:templates/admin/[你的APP名]/aaa/change_list.html(路径需对应你的APP和模型):

{% extends 'unfold/change_list.html' %}

{% block content %}
    {{ block.super }} {# 渲染原有的AAA列表表格 #}

    {# BBB预览表格容器 #}
    <div id="bbb-preview-container" class="module" style="margin-top: 20px; {% if not selected_aaa_id %}display: none;{% endif %}">
        {% if selected_aaa_id %}
            <h2>AAA: {{ selected_aaa.name }} 关联的BBB列表</h2>
            <table class="table">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>BBB标题</th>
                        {# 可添加其他BBB字段 #}
                    </tr>
                </thead>
                <tbody>
                    {% for bbb in bbb_list %}
                        <tr>
                            <td>{{ bbb.id }}</td>
                            <td>{{ bbb.title }}</td>
                            {# 渲染其他BBB字段 #}
                        </tr>
                    {% empty %}
                        <tr>
                            <td colspan="2">暂无关联的BBB对象</td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>
        {% endif %}
    </div>
{% endblock %}

{# 可选:添加AJAX无刷新加载的JS #}
{% block extrajs %}
    {{ block.super }}
    <script>
        // 给所有预览按钮绑定点击事件
        document.querySelectorAll('.button-small').forEach(btn => {
            if (btn.textContent.trim() === '预览BBB') {
                btn.addEventListener('click', function(e) {
                    e.preventDefault();
                    const aaaId = this.href.split('aaa_id=')[1];
                    const container = document.getElementById('bbb-preview-container');

                    // 发送AJAX请求
                    fetch(`?aaa_id=${aaaId}&ajax=1`)
                        .then(res => res.json())
                        .then(data => {
                            // 动态渲染表格
                            let tableHtml = `<h2>AAA: ${data.aaa_name} 关联的BBB列表</h2>`;
                            tableHtml += '<table class="table"><thead><tr><th>ID</th><th>BBB标题</th></tr></thead><tbody>';
                            
                            if (data.bbb_list.length === 0) {
                                tableHtml += '<tr><td colspan="2">暂无关联的BBB对象</td></tr>';
                            } else {
                                data.bbb_list.forEach(bbb => {
                                    tableHtml += `<tr><td>${bbb.id}</td><td>${bbb.title}</td></tr>`;
                                });
                            }
                            
                            tableHtml += '</tbody></table>';
                            container.innerHTML = tableHtml;
                            container.style.display = 'block';
                        });
                });
            }
        });
    </script>
{% endblock %}

关键注意事项

  • 模板路径:确保模板文件放在正确的位置,Django能找到(通常是[APP]/templates/admin/[模型小写名]/change_list.html)
  • UnFold样式兼容:使用UnFold内置的button、button-small、table等类,保证预览区域和原有UI风格一致
  • AJAX优化:如果不想页面刷新,可使用上述AJAX方案,提升用户体验
  • 权限控制:如果有特殊权限需求,可在changelist_view中添加权限校验,确保只有管理员能查看关联数据

内容的提问来源于stack exchange,提问作者Shahar Gino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 17:22:16