NetBox 自定义字段(Custom Fields)完全指南:从建模、配置到 REST/GraphQL API 与生命周期管理
NetBox 自定义字段Custom Fields完全指南从建模、配置到 REST/GraphQL API 与生命周期管理【免费下载链接】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 中的自定义字段Custom Fields为每个模型提供了高度灵活的元数据扩展能力你可以在不改动核心数据库表结构的前提下为 Site、Device、Prefix 等对象挂接任意类型的附加属性如内部工单号、业务标签、维护窗口并让这些字段自动融入 Web UI、表单、过滤器、导出模板以及 REST/GraphQL API。本文以 NetBox 官方文档《Custom Fields》为骨架结合当前仓库中的模型、选项与配置源码系统讲解自定义字段的类型体系、创建与校验规则、字段生命周期状态机以及它们在 Jinja2 模板与两类 API 中的实际用法帮助你在生产环境中安全、高效地落地自定义字段。自定义字段的定位为什么需要它NetBox 中每个模型在数据库里都是一张独立的表模型的每个属性对应表中的一个列。例如站点存储在dcim_site表中包含name、facility、physical_address等列。随着 NetBox 的发展新属性会不断被加入并扩展这些表。但有些用户需要记录的属性相当小众把它们写进 NetBox 核心数据库模式并不合理。例如你的组织希望把每台设备与内部支持系统中的工单号关联起来——这对 NetBox 是合理用法但不足以让每个 NetBox 安装都为它内置一个字段。此时就可以创建一个自定义字段来承载这类数据。从存储实现上看自定义字段值以 JSON 形式直接保存在对象旁边启用自定义字段支持的模型都带有一个custom_field_dataJSON 字段见 netbox/netbox/models/features.py 中的CustomFieldsMixin。这种设计免去了检索对象时编写复杂关联查询的麻烦——数据随对象存储、随对象读取。自定义字段的类型体系在 Web 界面中通过Customization Custom Fields创建自定义字段。NetBox 支持 13 种字段类型源码中定义于 netbox/extras/choices.py 的CustomFieldTypeChoices其语义如下类型存储值说明Text字符串自由文本面向单行使用Text (long)字符串任意长度文本支持 Markdown 渲染Integer整数正数或负数的整数Decimal小数固定精度小数4 位小数Boolean布尔True / FalseDate日期ISO 8601 格式YYYY-MM-DDDate time日期时间ISO 8601 格式YYYY-MM-DD HH:MM:SSURL字符串在 Web UI 中以链接呈现取值受ALLOWED_URL_SCHEMES允许的 scheme 限制未带 scheme 的值如example.com默认视为https并按绝对 URL 存储https://example.comJSON任意 JSON以 JSON 格式存储的任意数据Selection字符串从预定义选项中单选Multiple selection字符串列表支持多选的选项字段Object对象主键由object_type指定的单个 NetBox 对象Multiple objects对象主键列表由object_type指定的一个或多个 NetBox 对象其中 URL 字段在源码中由LaxURLField(assume_schemehttps, ...)实现见 netbox/extras/models/customfields.pyALLOWED_URL_SCHEMES的默认值为file, ftp, ftps, http, https, irc, mailto, sftp, ssh, tel, telnet, tftp, vnc, xmpp见 netbox/netbox/config/parameters.py。创建自定义字段基本属性每个自定义字段必须有一个名称name它应当是数据库友好的字符串如tps_report且只能包含字母数字字符和下划线。源码中的正则校验为^[a-z0-9_]$并且额外禁止出现双下划线__见 netbox/extras/models/customfields.py名称在全局范围内必须唯一。创建时还需要关注以下属性Label标签面向用户的可读名称如 TPS report显示在 Web 表单上未提供时界面直接使用 name。Weight权重必填。权重越高的字段在表单中排得越靠下默认值为 100。模型默认排序为[group_name, weight, name]见 netbox/extras/models/customfields.py。Description描述若提供会显示在表单中该字段的下方源码中会以 Markdown 渲染为help_text。Required必填标记后创建新对象或保存既有对象时强制用户提供值。Default默认值可为字段设置默认值布尔字段用true/false选择字段必须使用某个选项的精确值。Object types对象类型一个自定义字段必须被指派到一个或多个模型。创建后字段会自动出现在这些模型的 Web UI 与 REST API 中。注意并非所有模型都支持自定义字段。默认值与数据回填行为注意NetBox v4.6.8 起行为有变化为了提升创建自定义字段的性能空字段值不再被预置pre-provisioned。除非字段设置了默认值否则创建自定义字段不会向已存在的对象写入任何值。从未被赋值的对象对字段不存储任何内容在 Web UI、REST API、GraphQL API 与导出中均报告为无值与显式存储null完全一致。这一点只有在直接查询底层custom_field_dataJSON 时才重要例如在自定义脚本中。字段的 key 在赋值之前并不存在于对象数据中因此请用obj.cf[field_name]或obj.custom_field_data.get(field_name)读取而不要直接下标访问。与之相反设置默认值时会在字段创建的那一刻把该值写入所有既有对象使其立即可被过滤。但如果字段已存在后再补设默认值不会回填无值的对象会继续保持无值直到下次保存。从源码看回填通过populate_initial_data()完成它使用jsonb_set仅为尚未持有该字段 key的对象写入默认值~Q(custom_field_data__has_keyself.name)因此操作是幂等的见 netbox/extras/models/customfields.py。字段状态Field Status生命周期状态机注意该行为在 NetBox v4.7.0 引入创建带默认值的自定义字段、以及删除自定义字段都需要重写字段所作用对象已存储的数据。当字段被指派给大量对象时这项工作无法在一次请求内完成于是会被交给后台任务执行字段随之报告自身状态状态含义Active字段已上线可正常使用Provisioning正在把字段的默认值写入既有对象Deleting正在从既有对象中移除字段数据是否需要后台任务取决于该字段全部关联对象类型的对象总数并对照配置参数BULK_UPDATE_CHUNK_SIZE判断——而不是看这些对象中有多少真正持有字段值。因此删除一个指派到大型表的字段即使字段完全没有数据也会被延迟处理NetBox 无法在不扫描整张表的情况下统计持有值的对象数而扫描整表正是这个阈值要避免的开销。BULK_UPDATE_CHUNK_SIZE的默认值为 5000必须是正整数或None见 netbox/netbox/settings.py。源码中的_exceeds_inline_limit()通过探测而非COUNT(*)统计行数——只数比上限多一个主键即停止保证在千万行表上与万行表开销相同见 netbox/extras/models/customfields.py。状态机带来的实际约束字段只有在Active状态下才存活。Provisioning 或 Deleting 期间字段不会出现在对象、表单、过滤器或两类 API 中其存储数据只由负责它的任务读写任务完成后字段才上线或彻底消失。期间新创建的对象不受影响——处于 Provisioning 的字段仍会为新对象提供默认值。源码中get_defaults_for_model()特意把 Provisioning 字段包含进来DATA_STATUSES (STATUS_ACTIVE, STATUS_PROVISIONING)因为回填任务只覆盖字段创建前已存在的对象见 netbox/extras/models/customfields.py。非 Active 字段在任务运行期间不可修改配置不能在被任务重写数据时变动包括继续指派对象类型、或撤销已有对象类型——此类改动会被拒绝直到字段重新上线。此约束在CustomField.clean()中强制实现见 netbox/extras/models/customfields.py。待删除的字段在数据清除完成前会一直占用其名称因此无法用旧值仍残留在对象上的名称新建字段也不能把既有字段重命名到该名称。这些操作要求有正在运行的后台工作进程rqworker。字段若因没有 worker 或任务失败而中途搁置将一直保持待处理状态直到任务运行完成。无论处于何种状态字段始终可以被删除。删除一个已待删除的字段会重新排队一个清除任务处于 Provisioning 的字段则没有等价的应用内重试手段需要从后台队列Admin System Background Tasks需 staff 账号重新入队其任务或者删除后重建。注意从自定义字段撤销对象类型仍然会立即从这些对象上移除字段数据并且在非常大的表上仍受请求超时限制重命名字段同理。过滤逻辑Filtering过滤逻辑控制按自定义字段过滤对象时的值匹配方式Loose宽松默认部分值匹配。例如精确过滤字符串 red 只匹配值 red而宽松过滤会匹配 red、red-orange 甚至 bored。Exact精确给定字符串必须与字段值完全匹配。Disabled禁用完全禁用按该字段过滤。对应选项定义于CustomFieldFilterLogicChoices见 netbox/extras/choices.py。从源码to_filter()可以看到宽松匹配在底层映射为icontains不区分大小写的子串查询且字段被包装进missing_key_aware_filter_factory使取反查询能正确匹配那些根本不携带该字段 key 的对象见 netbox/extras/models/customfields.py。分组Grouping相关自定义字段可以在 UI 内分组给它们赋予相同的组名group name。当某个对象类型至少有一个字段定义了分组时这些字段会显示在对象视图的自定义字段面板中对应分组标题之下组名必须完全一致否则每个都会显示为独立标题。注意该参数对 API 中的自定义字段数据表示没有任何影响。模型层面的排序索引为(group_name, weight, name)即按组名、权重、名称顺序组织展示见 netbox/extras/models/customfields.py。可见性与可编辑性Visibility Editing创建字段时可控制其在 NetBox UI 中的显示与编辑条件。显示控制有三个选项Always始终默认查看对象时总是包含该字段。If Set已设置时仅当对象已定义该字段值时显示。Hidden隐藏UI 中永不显示推荐用于不面向人工用户的字段。编辑控制也有三个选项Yes是默认编辑对象时可修改字段值。No否编辑对象时字段仅作展示不可修改。Hidden隐藏编辑对象时不显示该字段。选项定义见CustomFieldUIVisibleChoices与CustomFieldUIEditableChoices见 netbox/extras/choices.py。注意该设置对 REST 与 GraphQL API 没有影响——自定义字段数据经 API 始终可用。UI 不可编辑的字段在表单层通过field.disabled True实现只读见 netbox/extras/models/customfields.py。值校验ValidationNetBox 对自定义字段值提供有限的自定义校验按字段类型区分字段类型校验规则Text正则表达式可选Integer最小值 / 最大值可选Decimal最小值 / 最大值可选Selection必须精确匹配预定义选项之一JSON必须符合定义的 JSON schema若有这些规则在CustomField.clean()中做了类型绑定约束最小/最大值仅可用于数值字段validation_minimum/validation_maximum最多 16 位、4 位小数正则仅可用于 Text、Long text 与 URL 字段validation_regex如^[A-Z]{3}$可将值限定为恰好三个大写字母JSON schema 仅可用于 JSON 字段validation_schema唯一性约束不能用于布尔字段见 netbox/extras/models/customfields.py。实际取值校验则在validate()中逐类型执行见 netbox/extras/models/customfields.py。选择字段Custom Selection Fields每个选择字段必须指定一个包含至少两个选项的选项集choice set选项以逗号分隔列表形式给出。若为选择字段指定默认值它必须精确匹配其中一个选项。多选字段的值总是返回列表即使只选了一个值。从源码看选项集CustomFieldChoiceSet还支持可选的基础选项集——内置了 IATA机场代码、ISO 3166国家代码、UN/LOCODE地点代码三套预置选项见 netbox/extras/choices.py以及字母序排序、选项配色等扩展能力见 netbox/extras/models/customfields.py。当从选项集中移除某个仍被对象引用的选项时保存会被拒绝以保证数据完整性。对象字段Custom Object FieldsObject / Multi-object 类型字段以某个 NetBox 对象或多个对象作为字段值。这类字段必须定义object_type它决定了字段实例指向的对象类型。默认情况下对象选择字段的下拉框会列出该类型全部对象。可以在 Related Object Filter 字段中以 JSON 形式提供query_params字典把候选对象过滤为仅包含特定值的那部分。query_params的更多说明见自定义脚本文档中的 ObjectVar 一节。源码中该过滤条件会被透传给DynamicModelChoiceField/DynamicModelMultipleChoiceField的query_params参数并在渲染时拼接到对象选择 API 请求中见 netbox/extras/models/customfields.py。在模板中使用自定义字段NetBox 的若干特性如导出模板、Webhook使用 Jinja2 模板。为了方便支持自定义字段的对象都通过cf属性暴露字段数据——这比直接读取custom_field_data字段更简洁。例如 Site 模型上一个名为foo123的自定义字段在实例上可写作{{ site.cf.foo123 }}该属性在源码中实现于CustomFieldsMixin.cf它为实例的每个自定义字段返回字段名 → 反序列化值的映射字典见 netbox/netbox/models/features.py。反序列化负责把 JSON 中的存储值还原为对应类型的 Python 对象例如把日期字符串还原为date、把 Object 字段的主键还原为实际对象见 netbox/extras/models/customfields.py。自定义字段与 REST API通过 REST API 检索对象时其全部自定义数据都会包含在custom_fields属性中。下面是一个定义了两个自定义字段的站点对象的部分输出{ id: 123, url: http://localhost:8000/api/dcim/sites/123/, name: Raleigh 42, ... custom_fields: { deployed: 2018-06-19, site_code: US-NC-RAL42 }, ...Selection 与 Multiple selection 字段会以对象形式返回同时携带存储值与面向人的标签与 NetBox 内置选项字段的约定一致custom_fields: { site_type: { value: datacenter, label: Data Center }, regions: [ { value: us-east, label: US East }, { value: us-west, label: US West } ] }, ...写入或修改这些值只需包含嵌套 JSON 数据例如{ name: New Site, slug: new-site, custom_fields: { deployed: 2019-03-24 } }与内置选项字段一致选择型自定义字段在写入时应传入原始值如site_type: datacenter而不是读取时返回的{value, label}对象。选择值的{value, label}解析在源码中由resolve_selection_value()统一实现REST 与 GraphQL 共用以保证两边表示一致见 netbox/extras/models/customfields.py。自定义字段与 GraphQL APIGraphQL API 的custom_fields字段同样会把 Selection 与 Multiple selection 值解析为{value, label}表示与 REST API 完全一致。换句话说通过 GraphQL 读取和过滤自定义字段时其行为约定与 REST API 保持对称你可以把上面 REST 一节中关于custom_fields嵌套对象的约定直接套用到 GraphQL 查询中。运维与性能要点大表操作必须依赖rqworker创建带默认值的字段、删除指派到大量对象的字段都可能转入后台任务Provisioning / Deleting 状态。请确保 background worker 正常运行否则字段会停留在待处理状态。任务失败后的恢复处于 Deleting 的字段可再次删除以重新排队清除任务处于 Provisioning 的字段需从Admin System Background Tasks重新入队任务需 staff 账号或删除后重建。修改被锁定的字段非 Active 字段在任务运行期间不可编辑、不可增删对象类型需等待其回到 Active。名称占用待删除字段会占用其名称直至数据清除完成避免新字段继承旧数据。写入与回填的幂等性populate_initial_data()与remove_stale_data()均只改写实际持有或不持有字段 key 的行且分批提交每批不超过BULK_UPDATE_CHUNK_SIZE行既避免超大 JSONB 更新语句触发数据库语句超时也让任务可安全重试见 netbox/extras/models/customfields.py。总结自定义字段是 NetBox 数据建模中最灵活、最常用的扩展机制13 种字段类型覆盖了从纯文本到对象引用的绝大多数附加数据需求JSON 就近存储的架构让读写都无需复杂关联v4.7.0 引入的字段状态机则让大表上的默认值回填与字段删除变得安全可控。无论你是想给设备挂接工单号、给站点补充业务分组还是通过 REST/GraphQL API 与自动化系统交换元数据都可以按照本文的配置路径、校验规则与 API 约定直接落地。更深入的字段模型定义、选项集管理与校验实现可继续查阅 customfields.py 模型源码、choices.py 选项定义 以及自定义字段模型文档。【免费下载链接】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),仅供参考