主页动态配置模块常见风险集中在配置错配与越权展示,表现为菜单缺失、组件顺序异常、跨公司配置被误读入渲染链路。

内容围绕 Home 的 HomeMenu 模块拆解,聚焦 company 参数约束、查询过滤条件、setting_data 配置承载方式与返回链路。
文章目录
需求解析
模块归属信息来自 Django AppConfig,路由注册来自 DRF DefaultRouter。
| 项目 | 材料依据 | 说明 |
|---|---|---|
| App 模块名 | Home/apps.py |
modules.HengShenGroup.Home |
| 路由注册 | Home/urls.py |
注册 Workbenches 与 HomeMenu 两个前缀 |
| 配置存储 | Home/models.py |
HomeMenu.setting_data 使用 JSONField |
| 过滤入口 | Home/views_app/HomeMenu.py |
get_queryset 基于登录态、company 参数、list 动作过滤 |
这里实现的是通过一套数据库管理,统一配置每个分公司/部门的可视化home面板,方便用户基于前端数据进行子女的一个调试。
数据筛选与返回
权限与范围约束
路由入口
进入模块路由
命中主页菜单入口
校验登录态
读取公司参数
校验公司范围
列表动作触发过滤
返回符合条件的数据集
功能实现
定位对象模块注册配置;目的说明:声明 Django 应用路径,保证模块可被加载。
python
from django.apps import AppConfig
class HomeConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "modules.HengShenGroup.Home"
需要注意的是 name 直接决定模块在工程内的定位路径。
定位对象:路由注册;目的说明:通过 DefaultRouter 暴露 HomeMenu 相关入口。
python
from rest_framework.routers import DefaultRouter
from dvadmin.utils.workbenches import WorkbenchesViewSet
from modules.HengShenGroup.Home.views_app.HomeMenu import HomeMenuViewSet
router = DefaultRouter()
router.register('Workbenches', WorkbenchesViewSet, 'Workbenches')
router.register('HomeMenu', HomeMenuViewSet, 'HomeMenu')
urlpatterns = [
# url(r'AccountsInfo', xxxx.as_view(), name='AccountsInfo')
]
urlpatterns += router.urls
需要注意的是 router.register('HomeMenu', ...) 直接固化了主页菜单相关请求的路由前缀。
定位对象数据模型;目的以公司维度存储主页配置数据,配置主体落在 JSON 字段中。
python
from django.db import models
from dvadmin.system.models import CoreModel
from dvadmin.utils.models import SoftDeleteModel
from plugins.dv3admin_flow.base_model import FlowBaseModel
# 主页菜单
class HomeMenu(CoreModel, SoftDeleteModel):
key = models.CharField(max_length=255, null=True, blank=True, verbose_name="键值")
company = models.CharField(max_length=255, null=True, blank=True, verbose_name='公司名称')
setting_data = models.JSONField(null=True, blank=True, verbose_name='配置数据')
class Meta:
db_table = 'HengShenGroup_Home_HomeMenu'
verbose_name = '各模块主页菜单'
verbose_name_plural = verbose_name
需要注意的是 company 与 key 均允许为空,过滤条件缺失时可能导致"空公司配置"被命中。
| 字段 | 类型 | 可空 | 用途 |
|---|---|---|---|
| key | CharField | 是 | 配置分类键值 |
| company | CharField | 是 | 公司范围标识 |
| setting_data | JSONField | 是 | 主页配置数据载体 |
定位对象迁移演进;目的展示主页配置字段调整轨迹,最终收敛到 JSON 配置与键值字段。
python
# Generated by Django 4.2.14 on 2025-09-30 08:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("Home", "0003_initial"),
]
operations = [
migrations.AddField(
model_name="homemenu",
name="enable",
field=models.BooleanField(
default=True, help_text="是否主页显示", verbose_name="是否启用"
),
),
]
这一步不能省略的校验点在于字段频繁变更时,线上数据与接口字段读取需要同步对齐。
python
# Generated by Django 4.2.14 on 2025-09-30 08:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("Home", "0004_homemenu_enable"),
]
operations = [
migrations.RemoveField(
model_name="homemenu",
name="enable",
),
migrations.RemoveField(
model_name="homemenu",
name="name_part",
),
migrations.AddField(
model_name="homemenu",
name="setting_data",
field=models.JSONField(blank=True, null=True, verbose_name="配置数据"),
),
]
需要注意的是 setting_data 被引入后,主页结构能力从"开关字段"转向"配置数据驱动"。
python
# Generated by Django 4.2.14 on 2025-11-13 08:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("Home", "0005_remove_homemenu_enable_remove_homemenu_name_part_and_more"),
]
operations = [
migrations.AddField(
model_name="homemenu",
name="key",
field=models.CharField(
blank=True, max_length=255, null=True, verbose_name="键值"
),
),
migrations.AlterField(
model_name="homemenu",
name="company",
field=models.CharField(
blank=True, max_length=255, null=True, verbose_name="公司名称"
),
),
]
需要注意的是 key 字段加入后,主页配置可以通过键值进行进一步分组与复用。
定位对象查询过滤;目的根据登录态与 company 参数限定可见配置范围,并在 list 动作中固定 key='home'。
python
# coding:utf-8
'''
@IDE :PyCharm
@Project :ManageBak-NDAY.py
@File :HomeMenu.py
@Author :Mr数据杨
@Date :2025/2/26
@Desc :
'''
from dvadmin.utils.viewset import CustomModelViewSet
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.json_response import SuccessResponse, ErrorResponse
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from dvadmin.system.models import DataVisualizationComponent
...
user = self.request.user
if not user or user.is_anonymous:
return qs.none()
company = self.request.query_params.get("company")
use_company = user.company # 登录后 user.company 才是安全的
if company is not None and company not in use_company:
return qs.none()
if self.action == "list":
qs = qs.filter(company=company, key='home')
return qs
需要注意的是 company not in use_company 属于包含判断,user.company 数据类型会直接影响判断语义与越权拦截效果。
| 过滤点 | 触发条件 | 结果 |
|---|---|---|
| 登录态校验 | user 为空或匿名 |
返回空数据集 |
| 公司范围校验 | company 存在且不在 user.company 范围 | 返回空数据集 |
| 列表动作过滤 | action 为 list | 追加 company=company 与 key='home' |
列表动作筛选
公司范围
鉴权入口
接入请求上下文
读取登录用户
匿名用户拦截
读取公司参数
读取用户公司范围
公司范围不匹配拦截
识别列表动作
限定主页配置范围
输出数据集
总结
主页动态配置的核心落点是 HomeMenu 表的 JSON 配置承载,以及 list 动作中对 key='home' 的固定过滤,路由入口通过 DefaultRouter 统一对外暴露。可优化空间集中在 company 参数为空时的过滤语义与空公司数据命中风险,以及 company not in use_company 的包含判断语义稳定性。
结构收敛到键值分组与 JSON 配置后,主页展示能够通过数据驱动稳定迭代,同时强化公司范围控制可提升维护性与权限边界稳定性。