如何在Django Admin中搭建站点-部门-岗位层级的内联管理视图
实现路径配置
前置准备
首先清理模型冗余问题,你当前models.py中存在多组重复语义的模型,会直接导致内联关联逻辑错乱:
- 存在两个标记为“部门”的模型:原生
Department、Section(verbose_name设为Department) - 存在两个标记为“岗位”的模型:
Position1、Question(verbose_name设为Position)
建议先移除Section、Question、Answer三个测试遗留模型的代码和注册逻辑,确认核心关联链路为: Site通过中间表关联对应部门、岗位(SiteHasDepartment、SiteHasPosition)Department通过外键关联下属Position1Position1通过外键关联下属日志Log、站点岗位指标SiteHasPosition
注意:Django Admin 原生内联仅支持2层嵌套,无法直接实现“Site→Department→Position→Log/SiteHasPosition”的纯嵌套折叠效果,可通过“逐层链接跳转+内联展示”的组合逻辑实现和前端视图一致的交互。
分步配置admin.py
1. 配置最内层岗位的关联内联
在岗位的编辑页挂载需要展示的日志、站点HC指标内联,默认折叠,点击展开:
from django.contrib import admin from .models import ( Site, Department, Position1, Log, SiteHasPosition, SiteHasDepartment ) # 日志内联:挂在岗位编辑页 class LogInline(admin.TabularInline): model = Log fields = ("user", "INN", "OUT", "date", "internal") extra = 0 # 隐藏默认空新增行 can_delete = False # 纯只读展示匹配需求 verbose_name = "岗位关联日志" # 站点岗位HC指标内联:挂在岗位编辑页 class SiteHasPositionInline(admin.TabularInline): model = SiteHasPosition fields = ("site", "date", "value", "standard", "turn_over") extra = 0 can_delete = False verbose_name = "站点岗位HC指标" @admin.register(Position1) class Position1Admin(admin.ModelAdmin): # 绑定下挂内联 inlines = [LogInline, SiteHasPositionInline] # 列表页展示核心字段 list_display = ("position", "jobID", "department", "hctype") # 支持按所属部门、所属站点筛选 list_filter = ("department__department", "log__site__site")
2. 配置部门层的关联内联
在部门的编辑页挂载下属岗位列表,点击部门即可看到所有关联岗位,岗位条目可直接点击跳转到详情页查看对应日志和指标:
# 岗位内联:挂在部门编辑页 class Position1Inline(admin.TabularInline): model = Position1 fields = ("position", "jobID", "hctype") extra = 0 can_delete = False verbose_name = "部门下属岗位" @admin.register(Department) class DepartmentAdmin(admin.ModelAdmin): inlines = [Position1Inline] list_display = ("department", "related_position_count") # 自定义方法统计部门下的岗位总数 def related_position_count(self, obj): return obj.position1_set.count() related_position_count.short_description = "关联岗位数"
3. 配置站点专属管理页
在站点编辑页挂载关联的部门、岗位列表,实现“选站点即看到全量关联部门/岗位”的效果:
# 站点关联部门内联:挂在站点编辑页 class SiteHasDepartmentInline(admin.TabularInline): model = SiteHasDepartment fields = ("department", "date", "value") extra = 0 verbose_name = "站点关联部门" # 站点关联岗位内联:挂在站点编辑页 class SiteHasPositionInline(admin.TabularInline): model = SiteHasPosition fields = ("position", "date", "value", "standard", "turn_over") extra = 0 verbose_name = "站点关联岗位" @admin.register(Site) class SiteAdmin(admin.ModelAdmin): inlines = [SiteHasDepartmentInline, SiteHasPositionInline] list_display = ("site", "totalHC") list_filter = ("totalHC",)
4. 自动过滤同站点匹配数据
重写内联类的外键过滤逻辑,自动根据当前选中的站点,筛选匹配的日志、指标数据,避免出现跨站点的无关内容:
# 以LogInline为例,添加外键过滤方法 def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "site": # 从当前页面上下文提取选中的站点ID current_site_id = request.resolver_match.kwargs.get("object_id") if current_site_id: kwargs["queryset"] = Site.objects.filter(id=current_site_id) return super().formfield_for_foreignkey(db_field, request, **kwargs)
相同逻辑可复用到SiteHasPositionInline中,实现数据自动匹配。
交互效果优化
- 所有内联组件添加
classes = ["collapse"]参数,设置为默认折叠状态,点击标题即可展开内容,和前端交互完全一致 - 在岗位列表页配置筛选快捷入口,从部门页跳转过来时自动过滤当前部门的岗位,无需手动筛选
- 纯只读展示场景下,将所有内联的
can_delete、extra参数配置为禁止新增、删除,避免误修改业务数据
内容的提问来源于stack exchange,提问作者Mar1941
相关产品推荐
相关产品推荐

