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

如何在Django Admin后台展示多对多关系的关联数据列表

实现方案

你可以通过两种原生方式实现需求,分别对应不同的使用场景:

方案1:重写模板实现类列表页样式(匹配你要的通用访客列表样式)

步骤1:调整Admin类注入关联数据

修改你的admin.py文件,分别给SiteAdmin和VisitorAdmin新增change_view方法,将关联对象查询集传入模板上下文:

from django.urls import reverse
from django.utils.html import format_html

# 你原有代码保留
class AdminArea(admin.AdminSite):
vms_admin = AdminArea(name='vms_admin')

@admin.register(Site, site=vms_admin)
class SiteAdmin(admin.ModelAdmin):
    # 保留你原有配置
    fieldsets = (*removed*)
    list_display = [*removed*]
    list_filter = (*removed*)

    def change_view(self, request, object_id, form_url='', extra_context=None):
        extra_context = extra_context or {}
        current_site = self.get_object(request, object_id)
        if current_site:
            # 传入关联访客数据
            extra_context['related_visitors'] = current_site.visitors.all()
        return super().change_view(request, object_id, form_url, extra_context=extra_context)

@admin.register(Visitor, site=vms_admin)
class VisitorAdmin(admin.ModelAdmin):
    # 保留你原有配置
    fieldsets = (*removed*)
    list_display = [*removed*]
    list_filter = (*removed*)

    def change_view(self, request, object_id, form_url='', extra_context=None):
        extra_context = extra_context or {}
        current_visitor = self.get_object(request, object_id)
        if current_visitor:
            # 传入关联站点数据
            extra_context['related_sites'] = current_visitor.site_set.all()
        return super().change_view(request, object_id, form_url, extra_context=extra_context)

步骤2:新增站点详情页自定义模板

在你项目的模板目录下创建路径admin/[你的应用名]/site/change_form.html,替换[你的应用名]为你models所在的app名称:

{% extends "admin/change_form.html" %}
{% block after_field_sets %}
{{ block.super }}
{% if related_visitors %}
<!-- 复用Django Admin自带样式类,和列表页视觉完全一致 -->
<div class="module">
    <h2>关联访客列表</h2>
    <table style="width: 100%" class="changelist-table">
        <thead>
            <tr>
                <th>访客姓名</th>
                <th>访客邮箱</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for visitor in related_visitors %}
            <tr class="{% cycle 'row1' 'row2' %}">
                <td>{{ visitor.name }}</td>
                <td>{{ visitor.email }}</td>
                <td>
                    <a href="{% url 'vms_admin:[你的应用名]_visitor_change' visitor.id %}">查看详情</a>
                </td>
            </tr>
            {% empty %}
            <tr><td colspan="3">暂无关联访客</td></tr>
            {% endfor %}
        </tbody>
    </table>
</div>
{% endif %}
{% endblock %}

步骤3:新增访客详情页自定义模板

在你项目的模板目录下创建路径admin/[你的应用名]/visitor/change_form.html:

{% extends "admin/change_form.html" %}
{% block after_field_sets %}
{{ block.super }}
{% if related_sites %}
<div class="module">
    <h2>关联站点列表</h2>
    <table style="width: 100%" class="changelist-table">
        <thead>
            <tr>
                <th>站点名称</th>
                <th>是否提供住宿</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for site in related_sites %}
            <tr class="{% cycle 'row1' 'row2' %}">
                <td>{{ site.name }}</td>
                <td>{{ site.accomodation|yesno:"是,否" }}</td>
                <td>
                    <a href="{% url 'vms_admin:[你的应用名]_site_change' site.id %}">查看详情</a>
                </td>
            </tr>
            {% empty %}
            <tr><td colspan="3">暂无关联站点</td></tr>
            {% endfor %}
        </tbody>
    </table>
</div>
{% endif %}
{% endblock %}

方案2:用内联(Inline)快速实现,无需编写模板

如果不需要完全匹配列表页样式,希望能直接在详情页编辑关联关系,可以用Django自带的内联组件:

# admin.py 新增内联类
class VisitorInline(admin.TabularInline):
    model = Site.visitors.through
    extra = 0
    readonly_fields = ['visitor_link']
    fields = ['visitor_link']

    def visitor_link(self, obj):
        return format_html(
            '<a href="{}">{}</a>',
            reverse('vms_admin:[你的应用名]_visitor_change', args=[obj.visitor.id]),
            obj.visitor.name
        )
    visitor_link.short_description = '关联访客'

class SiteInline(admin.TabularInline):
    model = Site.visitors.through
    extra = 0
    readonly_fields = ['site_link']
    fields = ['site_link']

    def site_link(self, obj):
        return format_html(
            '<a href="{}">{}</a>',
            reverse('vms_admin:[你的应用名]_site_change', args=[obj.site.id]),
            obj.site.name
        )
    site_link.short_description = '关联站点'

# 给对应的Admin类添加内联
@admin.register(Site, site=vms_admin)
class SiteAdmin(admin.ModelAdmin):
    # 原有配置保留
    inlines = [VisitorInline]

@admin.register(Visitor, site=vms_admin)
class VisitorAdmin(admin.ModelAdmin):
    # 原有配置保留
    inlines = [SiteInline]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 05:39:03