资讯详情

NetBox 插件开发指南:数据库模型(Database Models)的创建、NetBox 功能集成与 ChoiceSet 用法

📅 2026/9/21 18:42:00 | 华诺云谱 👁 阅读
NetBox 插件开发指南:数据库模型(Database Models)的创建、NetBox 功能集成与 ChoiceSet 用法
NetBox 插件开发指南数据库模型Database Models的创建、NetBox 功能集成与 ChoiceSet 用法【免费下载链接】netboxThe premier source of truth powering network automation. Open source under Apache 2. Try NetBox Cloud free: https://netboxlabs.com/products/free-netbox-cloud/项目地址: https://gitcode.com/gh_mirrors/ne/netboxNetBox 插件允许在核心对象之外引入全新的数据模型以支撑自定义业务对象如专有的资产类型、工单状态等。本文以官方文档 docs/plugins/development/models.md 为骨架系统讲解如何在插件中定义 Django 模型、通过继承NetBoxModel及其功能 Mixin 启用标签、自定义字段、变更日志、事件规则等 NetBox 原生能力并深入剖析数据库迁移、register_model_feature()自定义功能注册以及ChoiceSet动态选项配置的底层实现。读完本文你将能够独立编写一个可被 NetBox 完整识别、支持核心特性的插件数据模型。插件中的 Django 模型从models.py开始插件本质上是与 NetBox 一同安装的独立 Django 应用因此插件引入新对象类型的最直接方式就是定义 Django 模型。模型是数据库表的 Python 表示其属性对应表中的列通过 Django 查询 可以创建、修改和删除模型实例。所有模型都必须定义在名为models.py的文件中这是 Django 自动发现模型类进而生成迁移、注册到管理后台的约定。一个最基础的双字段示例来自原文档可直接复制运行from django.db import models class MyModel(models.Model): foo models.CharField(max_length50) bar models.CharField(max_length50) def __str__(self): return f{self.foo} {self.bar}每个模型默认包含一个由数据库自动生成的自增数值主键可通过pk或id引用。注意命名规范模型类名应遵循 PEP8 的 CapWords 风格首字母大写的驼峰式不要使用下划线。模型名中若出现下划线会导致权限系统出现问题因为 NetBox 的权限机制会基于模型名解析动作权限。启用 NetBox 功能继承NetBoxModel仅仅定义一个普通的models.Model只能获得 Django 提供的基础能力。若希望插件模型能复用 NetBox 的标签tags、自定义字段custom fields、事件规则event rules、自定义链接、变更日志、书签、通知、导出模板等功能必须继承 NetBox 提供的NetBoxModel基类。从源码看该基类承担两项关键职责见 netbox/netbox/models/init.py 及 netbox/netbox/models/features.py提供功能运行所需的字段、方法和属性——例如ChangeLoggingMixin自动追加created/last_updated时间戳CustomFieldsMixin增加custom_field_dataJSON 字段TagsMixin通过NetBoxTaggableManagerField提供tags管理属性见 netbox/netbox/models/features.py将模型注册为“使用这些功能”——NetBox 的register_models()会依据模型继承的 Mixin 自动注册相应功能视图如变更日志页、标签页见 netbox/netbox/models/features.py。定义方式非常简单# models.py from django.db import models from netbox.models import NetBoxModel class MyModel(NetBoxModel): foo models.CharField() ...NetBoxModel的完整功能集合定义在NetBoxFeatureSet中见 netbox/netbox/models/init.py其组合了BookmarksMixin、ChangeLoggingMixin、CloningMixin、CustomFieldsMixin、CustomLinksMixin、CustomValidationMixin、ExportTemplatesMixin、JournalingMixin、NotificationsMixin、TagsMixin与EventRulesMixin。同时NetBoxModel继承自BaseModel见 netbox/netbox/models/init.py后者对 Django 默认行为做了重要增强默认管理器替换为RestrictedQuerySet.as_manager()使对象查询自动受权限过滤clean()与save()会校验 GenericForeignKey 字段并把“可空且唯一”的 CharField 空字符串强制转为None避免 PostgreSQL 将空串视为重复值而触发唯一性冲突。NetBoxModel属性docs_url与_netbox_privateNetBoxModel还提供了两个可供插件覆盖/使用的属性docs_url指定该模型文档的访问 URL。默认返回/static/docs/models/app_label/model_name/见 netbox/netbox/models/init.py。插件模型可覆盖此属性例如指向插件自建在 ReadTheDocs 上的文档。_netbox_private默认情况下插件模型会出现在“通用对象类型”列表中例如创建自定义字段或某些仪表盘部件时的候选对象。如果模型仅供“幕后使用”、不应暴露给终端用户可将_netbox_private设为True将其从通用对象类型列表中剔除。其判定逻辑位于model_is_public()见 netbox/netbox/models/features.py只有app_label属于核心应用或PluginConfig的应用且未标记_netbox_private的模型才视为“公开可用”。按需启用功能使用独立 Mixin如果只想启用上述功能的子集NetBox 为每个功能提供了独立的“混合mix-in”类。定义模型时分别继承这些 Mixin 即可注意此时仍需继承 Django 内置的Model类。例如仅支持标签与导出模板# models.py from django.db import models from netbox.models.features import ExportTemplatesMixin, TagsMixin class MyModel(ExportTemplatesMixin, TagsMixin, models.Model): foo models.CharField() ...继承所有可用的 Mixin 在效果上等同于直接继承NetBoxModel。需要特别留意的是官方文档明确给出警告只有文档中列出的 Mixin 才受官方支持features模块中出现的其他类如ImageAttachmentsMixin、SyncedDataMixin、NotificationsMixin等——尽管核心模型在用目前不支持被插件使用插件应只依赖文档公开承诺的 API。内置扩展模型类PrimaryModel、OrganizationalModel 与 NestedGroupModel除了NetBoxModel基类NetBox 还额外提供了三类开箱即用的模型基类方便插件按对象性质选择。它们均在 NetBox v4.5 中纳入插件 API定义于 netbox/netbox/models/init.pyPrimaryModel主模型适用于绝大多数“真实对象”类型。它在NetBoxModel的基础上扩展了description与comments字段并引入所有权ownership支持通过OwnerMixin提供owner字段字段必填唯一说明owner否否对象的所有者description否否对象的人类可读描述CharField最长 200 字符comments否否通用备注TextField字段定义可对照 netbox/netbox/models/init.py 源码。OrganizationalModel组织模型用于主要承担“组织/归类其他对象”职能的对象类型如设备角色、区域等。字段如下见 netbox/netbox/models/init.py字段必填唯一说明name是是对象名称CharField最长 100 字符slug是是唯一的 URL 友好标识SlugFieldowner否否对象的所有者description否否对象的人类可读描述NestedGroupModel嵌套分组模型用于可递归排列成层级结构的对象如同 Region、Location通过自引用的parent外键实现。其字段如下字段必填唯一说明name是是对象名称slug是是唯一的 URL 友好标识parent否否将该对象嵌套于其下的同类型对象owner否否对象的所有者description否否对象的人类可读描述comments否否通用备注需要说明的是当前仓库中NestedGroupModel仍是基于 django-mptt 的实现见 netbox/netbox/models/init.py但其源码注释明确指出新代码包括插件应使用NestedLtreeGroupModel基于 PostgreSQL ltree见同文件 L231-L262MPTT 版本仅为向后兼容而保留将在未来版本中移除。因此新插件应优先使用NestedLtreeGroupModel来实现层级对象。数据库迁移从makemigrations到migrate模型定义完成后需要为其生成数据库模式迁移。迁移文件本质上是指导 PostgreSQL 数据库创建新表或修改既有表的一组指令。多数情况下可用 Django 的makemigrations管理命令自动生成——前提是插件已安装并启用否则 Django 无法找到该应用。提示开启开发者模式NetBox 对makemigrations命令设有保护防止普通用户误生成错误的模式迁移。插件开发时需在configuration.py中设置DEVELOPERTrue才能使用该命令。生成迁移$ ./manage.py makemigrations my_plugin Migrations for my_plugin: /home/jstretch/animal_sounds/my_plugin/migrations/0001_initial.py - Create model MyModel然后应用迁移$ ./manage.py migrate my_plugin Operations to perform: Apply all migrations: my_plugin Running migrations: Applying my_plugin.0001_initial... OK迁移目录migrations/是插件标准结构的一部分参见 docs/plugins/development/index.md 中的插件结构示例。更多迁移机制可参阅 Django 迁移文档。功能 Mixin 参考Feature Mixins ReferenceNetBox 为插件官方支持以下功能 Mixin均可从netbox.models.features导入插件可按需组合Mixin 类启用能力源码实现要点BookmarksMixin用户书签通过GenericRelation关联extras.BookmarkChangeLoggingMixin变更日志追加created/last_updated字段提供snapshot()、to_objectchange()配合ChangeLoggingMiddleware记录变更CloningMixin对象克隆提供clone()方法按clone_fields复制属性以预填充创建表单ContactsMixin联系人分配通过ContactAssignment关联联系人get_contacts()可继承父对象联系人CustomLinksMixin自定义链接使模型可作为自定义链接的目标CustomFieldsMixin自定义字段增加custom_field_dataJSON 字段及cf/custom_fields访问器并在clean()/save()中校验、填充默认值CustomValidationMixin自定义校验在clean()中发送post_clean信号供自定义校验规则挂钩EventRulesMixin事件规则使模型可挂接事件规则Webhook、自动执行脚本ExportTemplatesMixin导出模板使模型支持导出模板JobsMixin任务结果关联core.Job提供get_latest_jobs()删除对象时分批清理关联任务JournalingMixin对象日志通过GenericRelation关联extras.JournalEntryTagsMixin标签提供NetBoxTaggableManager类型的tags字段支持多个应用中同名模型的倒置访问器去冲突以上各类的具体实现均位于 netbox/netbox/models/features.py。NetBox 核心正是通过如下方式在启动时把“功能名 → 判定函数”注册进registry[model_features]见同文件 L705-L719register_model_feature(bookmarks, lambda model: issubclass(model, BookmarksMixin)) register_model_feature(custom_fields, lambda model: issubclass(model, CustomFieldsMixin)) register_model_feature(tags, lambda model: issubclass(model, TagsMixin)) # ... 其余功能同理随后has_feature()/get_model_features()见 netbox/netbox/models/features.py在运行时查询模型支持的功能集合。自定义模型功能register_model_feature()除了使用 NetBox 原生提供的模型功能插件还可以注册自己的模型功能。这通过netbox.utils中的register_model_feature()函数完成见 netbox/netbox/utils.py。该函数接受两个参数功能名称以及一个接收模型类的可调用对象该可调用对象必须返回布尔值指示给定模型是否支持该功能。从源码看其实现会把name → func写入全局registry[model_features]若同名功能已注册会抛出ValueError。函数既可作为装饰器使用register_model_feature(foo) def supports_foo(model): # Your logic here也可直接调用register_model_feature(foo, supports_foo)建议最好在插件PluginConfig的ready()方法中执行功能注册确保应用加载完成、模型可用之后再注册判定逻辑。注册完成后该自定义功能即与 NetBox 原生功能一样可被has_feature()、get_model_features()等查询并能在 UI/API 层作为该模型的特性被识别和展示。ChoiceSet为模型字段定义可动态配置的选项对于需要从预定义列表中选择一个或多个值的模型字段NetBox 提供了ChoiceSet工具类可替代 Django 原生 choices 元组带来两项增强能力动态配置与颜色标记模型级消费者可通过get_FOO_color()获取颜色映射见 netbox/utilities/choices.py。定义 ChoiceSet为模型字段定义选项时继承ChoiceSet并定义一个名为CHOICES的元组/列表每个成员是二元素或三元素元组数据库值value人类可读标签label分配的颜色可选color约定建议将每个数据库值声明为类上的常量并在CHOICES成员中引用这些常量这样可以在类外部引用这些值例如作为字段默认值。此约定非强制。动态配置key与FIELD_CHOICESNetBox 中部分模型字段的选项可由管理员配置例如 Site 模型status字段的默认选项可以被替换或补充。要为某个ChoiceSet子类启用动态配置需将其key定义为“模型.字段”形式的字符串from utilities.choices import ChoiceSet class StatusChoices(ChoiceSet): key MyModel.status随后NetBox 管理员可通过FIELD_CHOICES配置参数扩展或替换该选项集的默认值。my_plugin中MyModel的status字段被引用为FIELD_CHOICES { my_plugin.MyModel.status: ( # Custom choices ) }对照 docs/configuration/data-validation.md 中的说明FIELD_CHOICES是“模型字段 → 选项列表”的字典每个选项必须包含数据库值和标签可选颜色不带后缀表示替换默认选项带后缀如my_plugin.MyModel.status表示追加到默认选项字段标识符大小写不敏感。从源码层面看netbox/utilities/choices.pyChoiceSetMeta元类在类创建时读取key并以{app}.{key}为键去settings.FIELD_CHOICES中查找替换/扩展配置找到replace_key则整体替换CHOICES否则查找replace_key 并将配置项追加到现有CHOICES。因此**CHOICES必须声明为可变的 list 而非 tuple**否则动态扩展会失败元类甚至会在key存在而CHOICES不是 list 时抛出ImproperlyConfigured。提示ChoiceSet还提供values()与as_enum()类方法可将选项集转为值列表或enum.Enum见 netbox/utilities/choices.py便于在代码中以类型安全方式引用选项值。完整示例以my_plugin插件为例先定义choices.py# choices.py from utilities.choices import ChoiceSet class StatusChoices(ChoiceSet): key MyModel.status STATUS_FOO foo STATUS_BAR bar STATUS_BAZ baz CHOICES [ (STATUS_FOO, Foo, red), (STATUS_BAR, Bar, green), (STATUS_BAZ, Baz, blue), ]再在models.py中引用# models.py from django.db import models from .choices import StatusChoices class MyModel(models.Model): status models.CharField( max_length50, choicesStatusChoices, defaultStatusChoices.STATUS_FOO )字段的choices参数直接传入StatusChoices类即可ChoiceSet实现了__iter__见 netbox/utilities/choices.py默认值引用类常量保证与CHOICES中的数据库值一致。之后管理员即可通过configuration.py中的FIELD_CHOICES动态调整my_plugin.MyModel.status的可用选项而无需改动插件代码——这正是ChoiceSet相比原生 choices 元组的核心优势。小结插件模型开发的核心路径可以归纳为三步定义模型 → 选择基类/Mixin 启用 NetBox 功能 → 生成并应用迁移。在此基础上register_model_feature()允许插件扩展 NetBox 的模型功能注册表ChoiceSet则让插件模型字段也能享受与核心模型一致的动态选项配置体验。建议新插件优先使用PrimaryModel/OrganizationalModel/NestedLtreeGroupModel等内置基类并只依赖 docs/plugins/development/models.md 与 docs/plugins/development/index.md 所承诺的受支持 API以确保在 NetBox 后续版本中的兼容性。【免费下载链接】netboxThe premier source of truth powering network automation. Open source under Apache 2. Try NetBox Cloud free: https://netboxlabs.com/products/free-netbox-cloud/项目地址: https://gitcode.com/gh_mirrors/ne/netbox创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。