如何在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
相关产品推荐
相关产品推荐

