Skip to content

数据库模型

创建模型

如果您的插件在NetBox中引入了新类型的对象,您可能希望为其创建一个Django模型。模型本质上是数据库表的Python表示,具有表示各个列的属性。可以使用查询创建、操作和删除模型的实例(对象)。模型必须在名为models.py的文件中定义。

以下是一个包含具有两个字符(文本)字段的模型的示例models.py文件:

from django.db import models

class MyModel(models.Model):
    foo = models.CharField(max_length=50)
    bar = models.CharField(max_length=50)

    def __str__(self):
        return f'{self.foo} {self.bar}'

每个模型默认包括一个数字主键。此值由数据库自动生成,并可以作为pkid引用。

注意

模型名称应遵循PEP8标准,并且采用CapWords(没有下划线)。在模型名称中使用下划线将导致权限问题。

启用NetBox功能

插件模型可以通过继承NetBox的NetBoxModel类来利用某些NetBox功能。此类扩展了插件模型以启用NetBox独有的功能,包括:

  • 书签
  • 更改日志
  • 克隆
  • 自定义字段
  • 自定义链接
  • 自定义验证
  • 导出模板
  • 记录日志
  • 标签
  • Webhooks

此类执行两个关键功能:

  1. 应用于这些功能的操作所需的任何字段、方法和/或属性
  2. 注册模型,表示该模型使用了这些功能

只需在定义插件中的模型时将其子类化为NetBoxModel

# models.py
from django.db import models
from netbox.models import NetBoxModel

class MyModel(NetBoxModel):
    foo = models.CharField()
    ...

NetBoxModel属性

docs_url

此属性指定可以访问此模型文档的URL。默认情况下,它将返回/static/docs/models/<app_label>/<model_name>/。插件模型可以覆盖此属性以返回自定义URL。例如,您可以将用户引导到托管在ReadTheDocs上的插件文档。

_netbox_private

默认情况下,插件引入的任何模型都将出现在可用对象类型的列表中,例如在创建自定义字段或某些仪表板小部件时。如果模型仅用于“幕后使用”且不应向最终用户公开,则将_netbox_private设置为True。这将从通用对象类型列表中省略它。

单独启用功能

如果您更喜欢仅为插件模型启用这些功能的子集,NetBox为每个功能提供了单独的“混合”类。在定义模型时,可以单独为每个功能子类化它们。(您的模型还需要继承自Django内置的Model类。)

例如,如果我们只想支持标签和导出模板,我们可以从NetBox的ExportTemplatesMixinTagsMixin类中继承,并从Django的Model类中继承(继承所有可用的混合类基本上与子类化NetBoxModel相同)。

# models.py
from django.db import models
from netbox.models.features import ExportTemplatesMixin, TagsMixin

class MyModel(ExportTemplatesMixin, TagsMixin, models.Model):
    foo = models.CharField()
    ...

数据库迁移

一旦您完成了为插件定义模型,就需要创建数据库模式迁移。迁移文件本质上是一组用于操作PostgreSQL数据库以支持新模型或更改现有模型的指令。通常可以使用Django的makemigrations管理命令自动创建迁移。(确保首先安装和启用了您的插件,否则找不到它。)

注意

NetBox在makemigrations命令周围执行了一项保护措施,以防止普通用户意外创建错误的模式迁移。为了在插件开发中启用此命令,请在configuration.py中设置DEVELOPER=True

$ ./manage.py makemigrations my_plugin 
Migrations for 'my_plugin':
  /home/jstretch/animal_sounds/my_plugin/migrations/0001_initial.py
    - Create model MyModel

接下来,我们可以使用migrate命令将迁移应用于数据库:

$ ./manage.py migrate my_plugin
Operations to perform:
  Apply all migrations: my_plugin
Running migrations:
  Applying my_plugin.0001_initial... OK

有关数据库迁移的更多信息,请参阅Django文档

功能混合参考

警告

请注意,目前仅支持出现在此文档中的类。虽然“features”模块中可能存在其他类,但它们尚不支持供插件使用。

BookmarksMixin (Model) django-model

Enables support for user bookmarks.

bookmarks: GenericRelation blank django-field nullable

bookmarks

ChangeLoggingMixin (Model) django-model

Provides change logging support for a model. Adds the created and last_updated fields.

created: DateTimeField blank django-field nullable

created

last_updated: DateTimeField blank django-field nullable

last updated

serialize_object(self, exclude=None)

Return a JSON representation of the instance. Models can override this method to replace or extend the default serialization logic provided by the serialize_object() utility function.

Parameters:

Name Type Description Default
exclude

An iterable of attribute names to omit from the serialized output

None

snapshot(self)

Save a snapshot of the object's current state in preparation for modification. The snapshot is saved as _prechange_snapshot on the instance.

to_objectchange(self, action)

Return a new ObjectChange representing a change made to this object. This will typically be called automatically by ChangeLoggingMiddleware.

CloningMixin (Model) django-model

Provides the clone() method used to prepare a copy of existing objects.

clone(self)

Returns a dictionary of attributes suitable for creating a copy of the current instance. This is used for pre- populating an object creation form in the UI. By default, this method will replicate any fields listed in the model's clone_fields list (if defined), but it can be overridden to apply custom logic.

class MyModel(NetBoxModel):
    def clone(self):
        attrs = super().clone()
        attrs['extra-value'] = 123
        return attrs

CustomLinksMixin (Model) django-model

Enables support for custom links.

CustomFieldsMixin (Model) django-model

Enables support for custom fields.

custom_field_data: JSONField blank django-field

custom field data

cf cached property writable

Return a dictionary mapping each custom field for this instance to its deserialized value.

>>> tenant = Tenant.objects.first()
>>> tenant.cf
{'primary_site': <Site: DM-NYC>, 'cust_id': 'DMI01', 'is_active': True}

custom_fields cached property writable

Return the QuerySet of CustomFields assigned to this model.

>>> tenant = Tenant.objects.first()
>>> tenant.custom_fields
<RestrictedQuerySet [<CustomField: Primary site>, <CustomField: Customer ID>, <CustomField: Is active>]>

get_custom_fields(self, omit_hidden=False)

Return a dictionary of custom fields for a single object in the form {field: value}.

>>> tenant = Tenant.objects.first()
>>> tenant.get_custom_fields()
{<CustomField: Customer ID>: 'CYB01'}

Parameters:

Name Type Description Default
omit_hidden

If True, custom fields with no UI visibility will be omitted.

False

get_custom_fields_by_group(self)

Return a dictionary of custom field/value mappings organized by group. Hidden fields are omitted.

>>> tenant = Tenant.objects.first()
>>> tenant.get_custom_fields_by_group()
{
    '': {<CustomField: Primary site>: <Site: DM-NYC>},
    'Billing': {<CustomField: Customer ID>: 'DMI01', <CustomField: Is active>: True}
}

populate_custom_field_defaults(self)

Apply the default value for each custom field

clean(self)

Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.

CustomValidationMixin (Model) django-model

Enables user-configured validation rules for models.

clean(self)

Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.

EventRulesMixin (Model) django-model

Enables support for event rules, which can be used to transmit webhooks or execute scripts automatically.

注意

EventRulesMixin在NetBox v3.7中从WebhooksMixin中更名而来。

ExportTemplatesMixin (Model) django-model

Enables support for export templates.

JournalingMixin (Model) django-model

Enables support for object journaling. Adds a generic relation (journal_entries) to NetBox's JournalEntry model.

journal_entries: GenericRelation blank django-field nullable

journal entries

TagsMixin (Model) django-model

Enables support for tag assignment. Assigned tags can be managed via the tags attribute, which is a TaggableManager instance.

tags: TaggableManager django-field nullable

Tags: A comma-separated list of tags.

选择集

对于支持从预定义选择列表中选择一个或多个值的模型字段,NetBox提供了ChoiceSet实用类。这可以用来替代常规的选择元组,以提供增强功能,即动态配置和着色。(有关受支持的模型字段的choices参数,请参阅Django文档。)

要为模型字段定义选择项,请子类化ChoiceSet并定义一个名为CHOICES的元组,其中每个成员都是一个两个或三个元组。这些元素是:

  • 数据库值
  • 相应的用户友好标签
  • 分配的颜色(可选)

下面提供了一个完整示例。

注意

作者可能会发现有用的是将每个数据库值声明为类上的常量,并在CHOICES成员内引用它们。这种约定允许从类外部引用这些值,但不是强制性的。

动态配置

NetBox中的某些模型字段选择可以由管理员配置。例如,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': (
        # 自定义选择
    )
}

示例

# 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'),
    ]

警告

为了使动态配置正常工作,CHOICES必须是可变列表,而不是元组。

# models.py
from django.db import models
from .choices import StatusChoices

class MyModel(models.Model):
    status = models.CharField(
        max_length=50,
        choices=StatusChoices,
        default=StatusChoices.STATUS_FOO
    )