Просмотр исходного кода

Merge branch 'feature' into 20925-comments-oranizationalmodel

bctiemann 2 месяцев назад
Родитель
Сommit
834da4e6cd

+ 8 - 0
docs/plugins/development/filtersets.md

@@ -32,6 +32,14 @@ class MyFilterSet(NetBoxModelFilterSet):
         fields = ('some', 'other', 'fields')
         fields = ('some', 'other', 'fields')
 ```
 ```
 
 
+In addition to the base NetBoxModelFilterSet class, the following filterset classes are also available for subclasses of standard base models.
+
+| Model Class           | FilterSet Class                                  |
+|-----------------------|--------------------------------------------------|
+| `PrimaryModel`        | `netbox.filtersets.PrimaryModelFilterSet`        |
+| `OrganizationalModel` | `netbox.filtersets.OrganizationalModelFilterSet` |
+| `NestedGroupModel`    | `netbox.filtersets.NestedGroupModelFilterSet`    |
+
 ### Declaring Filter Sets
 ### Declaring Filter Sets
 
 
 To utilize a filter set in a subclass of one of NetBox's generic views (such as `ObjectListView` or `BulkEditView`), define the `filterset` attribute on the view class:
 To utilize a filter set in a subclass of one of NetBox's generic views (such as `ObjectListView` or `BulkEditView`), define the `filterset` attribute on the view class:

+ 46 - 6
docs/plugins/development/forms.md

@@ -2,7 +2,7 @@
 
 
 ## Form Classes
 ## Form Classes
 
 
-NetBox provides several base form classes for use by plugins.
+NetBox provides several base form classes for use by plugins. Additional form classes are also available for other standard base model classes (PrimaryModel, OrganizationalModel, and NestedGroupModel).
 
 
 | Form Class                 | Purpose                              |
 | Form Class                 | Purpose                              |
 |----------------------------|--------------------------------------|
 |----------------------------|--------------------------------------|
@@ -19,7 +19,17 @@ This is the base form for creating and editing NetBox models. It extends Django'
 |-------------|---------------------------------------------------------------------------------------|
 |-------------|---------------------------------------------------------------------------------------|
 | `fieldsets` | A tuple of `FieldSet` instances which control how form fields are rendered (optional) |
 | `fieldsets` | A tuple of `FieldSet` instances which control how form fields are rendered (optional) |
 
 
-**Example**
+#### Subclasses
+
+The corresponding model-specific subclasses of `NetBoxModelForm` are documented below.
+
+| Model Class           | Form Class                |
+|-----------------------|---------------------------|
+| `PrimaryModel`        | `PrimaryModelForm`        |
+| `OrganizationalModel` | `OrganizationalModelForm` |
+| `NestedGroupModel`    | `NestedGroupModelForm`    |
+
+#### Example
 
 
 ```python
 ```python
 from django.utils.translation import gettext_lazy as _
 from django.utils.translation import gettext_lazy as _
@@ -49,9 +59,19 @@ class MyModelForm(NetBoxModelForm):
 
 
 ### `NetBoxModelImportForm`
 ### `NetBoxModelImportForm`
 
 
-This form facilitates the bulk import of new objects from CSV, JSON, or YAML data. As with model forms, you'll need to declare a `Meta` subclass specifying the associated `model` and `fields`. NetBox also provides several form fields suitable for import various types of CSV data, listed below.
+This form facilitates the bulk import of new objects from CSV, JSON, or YAML data. As with model forms, you'll need to declare a `Meta` subclass specifying the associated `model` and `fields`. NetBox also provides several form fields suitable for importing various types of CSV data, listed [below](#csv-import-fields).
+
+#### Subclasses
+
+The corresponding model-specific subclasses of `NetBoxModelImportForm` are documented below.
+
+| Model Class           | Form Class                      |
+|-----------------------|---------------------------------|
+| `PrimaryModel`        | `PrimaryModelImportForm`        |
+| `OrganizationalModel` | `OrganizationalModelImportForm` |
+| `NestedGroupModel`    | `NestedGroupModelImportForm`    |
 
 
-**Example**
+#### Example
 
 
 ```python
 ```python
 from django.utils.translation import gettext_lazy as _
 from django.utils.translation import gettext_lazy as _
@@ -83,7 +103,17 @@ This form facilitates editing multiple objects in bulk. Unlike a model form, thi
 | `fieldsets`       | A tuple of `FieldSet` instances which control how form fields are rendered (optional)       |
 | `fieldsets`       | A tuple of `FieldSet` instances which control how form fields are rendered (optional)       |
 | `nullable_fields` | A tuple of fields which can be nullified (set to empty) using the bulk edit form (optional) |
 | `nullable_fields` | A tuple of fields which can be nullified (set to empty) using the bulk edit form (optional) |
 
 
-**Example**
+#### Subclasses
+
+The corresponding model-specific subclasses of `NetBoxModelBulkEditForm` are documented below.
+
+| Model Class           | Form Class                        |
+|-----------------------|-----------------------------------|
+| `PrimaryModel`        | `PrimaryModelBulkEditForm`        |
+| `OrganizationalModel` | `OrganizationalModelBulkEditForm` |
+| `NestedGroupModel`    | `NestedGroupModelBulkEditForm`    |
+
+#### Example
 
 
 ```python
 ```python
 from django import forms
 from django import forms
@@ -125,7 +155,17 @@ This form class is used to render a form expressly for filtering a list of objec
 | `model`     | The model of object being edited                                                      |
 | `model`     | The model of object being edited                                                      |
 | `fieldsets` | A tuple of `FieldSet` instances which control how form fields are rendered (optional) |
 | `fieldsets` | A tuple of `FieldSet` instances which control how form fields are rendered (optional) |
 
 
-**Example**
+#### Subclasses
+
+The corresponding model-specific subclasses of `NetBoxModelFilterSetForm` are documented below.
+
+| Model Class           | Form Class                         |
+|-----------------------|------------------------------------|
+| `PrimaryModel`        | `PrimaryModelFilterSetForm`        |
+| `OrganizationalModel` | `OrganizationalModelFilterSetForm` |
+| `NestedGroupModel`    | `NestedGroupModelFilterSetForm`    |
+
+#### Example
 
 
 ```python
 ```python
 from dcim.models import Site
 from dcim.models import Site

+ 16 - 0
docs/plugins/development/graphql-api.md

@@ -46,3 +46,19 @@ NetBox provides two object type classes for use by plugins.
 ::: netbox.graphql.types.NetBoxObjectType
 ::: netbox.graphql.types.NetBoxObjectType
     options:
     options:
       members: false
       members: false
+
+## GraphQL Filters
+
+NetBox provides a base filter class for use by plugins which employ subclasseses of `NetBoxModel`.
+
+::: netbox.graphql.filters.NetBoxModelFilter
+    options:
+      members: false
+
+Additionally, the following filter classes are available for subclasses of standard base models.
+
+| Model Class           | FilterSet Class                                    |
+|-----------------------|----------------------------------------------------|
+| `PrimaryModel`        | `netbox.graphql.filters.PrimaryModelFilter`        |
+| `OrganizationalModel` | `netbox.graphql.filters.OrganizationalModelFilter` |
+| `NestedGroupModel`    | `netbox.graphql.filters.NestedGroupModelFilter`    |

+ 40 - 0
docs/plugins/development/models.md

@@ -67,6 +67,46 @@ class MyModel(ExportTemplatesMixin, TagsMixin, models.Model):
     ...
     ...
 ```
 ```
 
 
+### Additional Models
+
+In addition to the base NetBoxModel class, the following additional classes are provided for convenience.
+
+!!! info "These model classes were added to the plugins API in NetBox v4.5."
+
+#### PrimaryModel
+
+PrimaryModel is the go-to class for most object types. It extends NetBoxModel with `description` and `comments` fields, and it introduces support for ownership assignment.
+
+| Field         | Required | Unique | Description                                 |
+|---------------|----------|--------|---------------------------------------------|
+| `owner`       | No       | No     | The object's owner                          |
+| `description` | No       | No     | A human-friendly description for the object |
+| `comments`    | No       | No     | General comments                            |
+
+#### OrganizationalModel
+
+OrganizationalModel is used by object types whose function is primarily the organization of other objects.
+
+| Field         | Required | Unique | Description                                 |
+|---------------|----------|--------|---------------------------------------------|
+| `name`        | Yes      | Yes    | The name of the object                      |
+| `slug`        | Yes      | Yes    | A unique URL-friendly identifier            |
+| `owner`       | No       | No     | The object's owner                          |
+| `description` | No       | No     | A human-friendly description for the object |
+
+#### NestedGroupModel
+
+NestedGroupModel is used for objects which arrange into a recursive hierarchy (like regions and locations) via its self-referential `parent` foreign key.
+
+| Field         | Required | Unique | Description                                                     |
+|---------------|----------|--------|-----------------------------------------------------------------|
+| `name`        | Yes      | Yes    | The name of the object                                          |
+| `slug`        | Yes      | Yes    | A unique URL-friendly identifier                                |
+| `parent`      | No       | No     | The object (of the same type) under which this object is nested |
+| `owner`       | No       | No     | The object's owner                                              |
+| `description` | No       | No     | A human-friendly description for the object                     |
+| `comments`    | No       | No     | General comments                                                |
+
 ## Database Migrations
 ## Database Migrations
 
 
 Once you have completed defining the model(s) for your plugin, you'll need to create the database schema migrations. A migration file is essentially a set of instructions for manipulating the PostgreSQL database to support your new model, or to alter existing models. Creating migrations can usually be done automatically using Django's `makemigrations` management command. (Ensure that your plugin has been installed and enabled first, otherwise it won't be found.)
 Once you have completed defining the model(s) for your plugin, you'll need to create the database schema migrations. A migration file is essentially a set of instructions for manipulating the PostgreSQL database to support your new model, or to alter existing models. Creating migrations can usually be done automatically using Django's `makemigrations` management command. (Ensure that your plugin has been installed and enabled first, otherwise it won't be found.)

+ 8 - 0
docs/plugins/development/rest-api.md

@@ -27,6 +27,14 @@ Serializers are responsible for converting Python objects to JSON data suitable
 
 
 The default nested representation of an object is defined by the `brief_fields` attributes under the serializer's `Meta` class. (Older versions of NetBox required the definition of a separate nested serializer.)
 The default nested representation of an object is defined by the `brief_fields` attributes under the serializer's `Meta` class. (Older versions of NetBox required the definition of a separate nested serializer.)
 
 
+In addition to the base NetBoxModelSerializer class, the following serializer classes are also available for subclasses of standard base models.
+
+| Model Class           | Serializer Class                                       |
+|-----------------------|--------------------------------------------------------|
+| `PrimaryModel`        | `netbox.api.serializers.PrimaryModelSerializer`        |
+| `OrganizationalModel` | `netbox.api.serializers.OrganizationalModelSerializer` |
+| `NestedGroupModel`    | `netbox.api.serializers.NestedGroupModelSerializer`    |
+
 #### Example
 #### Example
 
 
 To create a serializer for a plugin model, subclass `NetBoxModelSerializer` in `api/serializers.py`. Specify the model class and the fields to include within the serializer's `Meta` class.
 To create a serializer for a plugin model, subclass `NetBoxModelSerializer` in `api/serializers.py`. Specify the model class and the fields to include within the serializer's `Meta` class.

+ 8 - 0
docs/plugins/development/tables.md

@@ -36,6 +36,14 @@ class MyModelTable(NetBoxTable):
         default_columns = ('pk', 'name', ...)
         default_columns = ('pk', 'name', ...)
 ```
 ```
 
 
+In addition to the base NetBoxTable class, the following table classes are also available for subclasses of standard base models.
+
+| Model Class           | Table Class                              |
+|-----------------------|------------------------------------------|
+| `PrimaryModel`        | `netbox.tables.PrimaryModelTable`        |
+| `OrganizationalModel` | `netbox.tables.OrganizationalModelTable` |
+| `NestedGroupModel`    | `netbox.tables.NestedGroupModelTable`    |
+
 ### Table Configuration
 ### Table Configuration
 
 
 The NetBoxTable class features dynamic configuration to allow users to change their column display and ordering preferences. To configure a table for a specific request, simply call its `configure()` method and pass the current HTTPRequest object. For example:
 The NetBoxTable class features dynamic configuration to allow users to change their column display and ordering preferences. To configure a table for a specific request, simply call its `configure()` method and pass the current HTTPRequest object. For example:

+ 3 - 2
netbox/dcim/api/serializers_/manufacturers.py

@@ -11,13 +11,14 @@ class ManufacturerSerializer(OrganizationalModelSerializer):
 
 
     # Related object counts
     # Related object counts
     devicetype_count = RelatedObjectCountField('device_types')
     devicetype_count = RelatedObjectCountField('device_types')
+    moduletype_count = RelatedObjectCountField('module_types')
     inventoryitem_count = RelatedObjectCountField('inventory_items')
     inventoryitem_count = RelatedObjectCountField('inventory_items')
     platform_count = RelatedObjectCountField('platforms')
     platform_count = RelatedObjectCountField('platforms')
 
 
     class Meta:
     class Meta:
         model = Manufacturer
         model = Manufacturer
         fields = [
         fields = [
-            'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'owner', 'comments', 'tags',
-            'custom_fields', 'created', 'last_updated', 'devicetype_count', 'inventoryitem_count', 'platform_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'owner', 'comments', 'tags', 'custom_fields',
+            'created', 'last_updated', 'devicetype_count', 'moduletype_count', 'inventoryitem_count', 'platform_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'devicetype_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'devicetype_count')

+ 12 - 16
netbox/netbox/forms/filtersets.py

@@ -45,10 +45,7 @@ class NetBoxModelFilterSetForm(FilterModifierMixin, CustomFieldsMixin, SavedFilt
         return customfield.to_form_field(set_initial=False, enforce_required=False, enforce_visibility=False)
         return customfield.to_form_field(set_initial=False, enforce_required=False, enforce_visibility=False)
 
 
 
 
-class PrimaryModelFilterSetForm(NetBoxModelFilterSetForm):
-    """
-    FilterSet form for models which inherit from PrimaryModel.
-    """
+class OwnerFilterMixin(forms.Form):
     owner_id = DynamicModelChoiceField(
     owner_id = DynamicModelChoiceField(
         queryset=Owner.objects.all(),
         queryset=Owner.objects.all(),
         required=False,
         required=False,
@@ -56,23 +53,22 @@ class PrimaryModelFilterSetForm(NetBoxModelFilterSetForm):
     )
     )
 
 
 
 
-class OrganizationalModelFilterSetForm(NetBoxModelFilterSetForm):
+class PrimaryModelFilterSetForm(OwnerFilterMixin, NetBoxModelFilterSetForm):
+    """
+    FilterSet form for models which inherit from PrimaryModel.
+    """
+    pass
+
+
+class OrganizationalModelFilterSetForm(OwnerFilterMixin, NetBoxModelFilterSetForm):
     """
     """
     FilterSet form for models which inherit from OrganizationalModel.
     FilterSet form for models which inherit from OrganizationalModel.
     """
     """
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
+    pass
 
 
 
 
-class NestedGroupModelFilterSetForm(NetBoxModelFilterSetForm):
+class NestedGroupModelFilterSetForm(OwnerFilterMixin, NetBoxModelFilterSetForm):
     """
     """
     FilterSet form for models which inherit from NestedGroupModel.
     FilterSet form for models which inherit from NestedGroupModel.
     """
     """
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
+    pass