18981 forms, serializer

This commit is contained in:
Arthur 2025-03-25 13:28:26 -07:00
parent b5b1827893
commit 0b153f42de
9 changed files with 90 additions and 8 deletions

View File

@ -4,6 +4,10 @@ Devices can be organized by functional roles, which are fully customizable by th
## Fields ## Fields
### Parent
The parent role of which this role is a child (optional).
### Name ### Name
A unique human-friendly name. A unique human-friendly name.

View File

@ -52,6 +52,13 @@ class NestedLocationSerializer(WritableNestedSerializer):
fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'rack_count', '_depth'] fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'rack_count', '_depth']
class NestedDeviceRoleSerializer(WritableNestedSerializer):
class Meta:
model = models.DeviceRole
fields = ['id', 'url', 'display_url', 'display', 'name']
class NestedDeviceSerializer(WritableNestedSerializer): class NestedDeviceSerializer(WritableNestedSerializer):
class Meta: class Meta:

View File

@ -1,7 +1,8 @@
from dcim.models import DeviceRole, InventoryItemRole from dcim.models import DeviceRole, InventoryItemRole
from extras.api.serializers_.configtemplates import ConfigTemplateSerializer from extras.api.serializers_.configtemplates import ConfigTemplateSerializer
from netbox.api.fields import RelatedObjectCountField from netbox.api.fields import RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer
from .nested import NestedDeviceRoleSerializer
__all__ = ( __all__ = (
'DeviceRoleSerializer', 'DeviceRoleSerializer',
@ -9,7 +10,8 @@ __all__ = (
) )
class DeviceRoleSerializer(NetBoxModelSerializer): class DeviceRoleSerializer(NestedGroupModelSerializer):
parent = NestedDeviceRoleSerializer(required=False, allow_null=True, default=None)
config_template = ConfigTemplateSerializer(nested=True, required=False, allow_null=True, default=None) config_template = ConfigTemplateSerializer(nested=True, required=False, allow_null=True, default=None)
# Related object counts # Related object counts
@ -19,10 +21,13 @@ class DeviceRoleSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = DeviceRole model = DeviceRole
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'vm_role', 'config_template', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'vm_role', 'config_template', 'parent',
'description', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count',
'_depth',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count') brief_fields = (
'id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count', '_depth'
)
class InventoryItemRoleSerializer(NetBoxModelSerializer): class InventoryItemRoleSerializer(NetBoxModelSerializer):

View File

@ -922,6 +922,29 @@ class DeviceRoleFilterSet(OrganizationalModelFilterSet):
queryset=ConfigTemplate.objects.all(), queryset=ConfigTemplate.objects.all(),
label=_('Config template (ID)'), label=_('Config template (ID)'),
) )
parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=DeviceRole.objects.all(),
label=_('Parent device role (ID)'),
)
parent = django_filters.ModelMultipleChoiceFilter(
field_name='parent__slug',
queryset=DeviceRole.objects.all(),
to_field_name='slug',
label=_('Parent device role (slug)'),
)
ancestor_id = TreeNodeMultipleChoiceFilter(
queryset=DeviceRole.objects.all(),
field_name='parent',
lookup_expr='in',
label=_('Parent device role (ID)'),
)
ancestor = TreeNodeMultipleChoiceFilter(
queryset=DeviceRole.objects.all(),
field_name='parent',
lookup_expr='in',
to_field_name='slug',
label=_('Parent device role (slug)'),
)
class Meta: class Meta:
model = DeviceRole model = DeviceRole

View File

@ -612,6 +612,11 @@ class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
parent = DynamicModelChoiceField(
label=_('Parent'),
queryset=DeviceRole.objects.all(),
required=False,
)
color = ColorField( color = ColorField(
label=_('Color'), label=_('Color'),
required=False required=False
@ -634,7 +639,7 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
model = DeviceRole model = DeviceRole
fieldsets = ( fieldsets = (
FieldSet('color', 'vm_role', 'config_template', 'description'), FieldSet('parent', 'color', 'vm_role', 'config_template', 'description'),
) )
nullable_fields = ('color', 'config_template', 'description') nullable_fields = ('color', 'config_template', 'description')

View File

@ -460,6 +460,16 @@ class ModuleTypeImportForm(NetBoxModelImportForm):
class DeviceRoleImportForm(NetBoxModelImportForm): class DeviceRoleImportForm(NetBoxModelImportForm):
parent = CSVModelChoiceField(
label=_('Parent'),
queryset=DeviceRole.objects.all(),
required=False,
to_field_name='name',
help_text=_('Parent Device Role'),
error_messages={
'invalid_choice': _('Device role not found.'),
}
)
config_template = CSVModelChoiceField( config_template = CSVModelChoiceField(
label=_('Config template'), label=_('Config template'),
queryset=ConfigTemplate.objects.all(), queryset=ConfigTemplate.objects.all(),
@ -471,7 +481,7 @@ class DeviceRoleImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = DeviceRole model = DeviceRole
fields = ('name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags') fields = ('name', 'slug', 'parent', 'color', 'vm_role', 'config_template', 'description', 'tags')
class PlatformImportForm(NetBoxModelImportForm): class PlatformImportForm(NetBoxModelImportForm):

View File

@ -689,6 +689,11 @@ class DeviceRoleFilterForm(NetBoxModelFilterSetForm):
required=False, required=False,
label=_('Config template') label=_('Config template')
) )
parent_id = DynamicModelMultipleChoiceField(
queryset=DeviceRole.objects.all(),
required=False,
label=_('Parent')
)
tag = TagFilterField(model) tag = TagFilterField(model)

View File

@ -430,17 +430,23 @@ class DeviceRoleForm(NetBoxModelForm):
required=False required=False
) )
slug = SlugField() slug = SlugField()
parent = DynamicModelChoiceField(
label=_('Parent'),
queryset=DeviceRole.objects.all(),
required=False,
)
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
'name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags', name=_('Device Role') 'name', 'slug', 'parent', 'color', 'vm_role', 'config_template', 'description',
'tags', name=_('Device Role')
), ),
) )
class Meta: class Meta:
model = DeviceRole model = DeviceRole
fields = [ fields = [
'name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags', 'name', 'slug', 'parent', 'color', 'vm_role', 'config_template', 'description', 'tags',
] ]

View File

@ -30,6 +30,10 @@
<th scope="row">{% trans "Description" %}</th> <th scope="row">{% trans "Description" %}</th>
<td>{{ object.description|placeholder }}</td> <td>{{ object.description|placeholder }}</td>
</tr> </tr>
<tr>
<th scope="row">{% trans "Parent" %}</th>
<td>{{ object.parent|linkify|placeholder }}</td>
</tr>
<tr> <tr>
<th scope="row">{% trans "Color" %}</th> <th scope="row">{% trans "Color" %}</th>
<td> <td>
@ -57,6 +61,19 @@
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col col-md-12"> <div class="col col-md-12">
<div class="card">
<h2 class="card-header">
{% trans "Child Device Roles" %}
{% if perms.dcim.add_devicerole %}
<div class="card-actions">
<a href="{% url 'dcim:devicerole_add' %}?parent={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-ghost-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add a Device Role" %}
</a>
</div>
{% endif %}
</h2>
{% htmx_table 'dcim:devicerole_list' parent_id=object.pk %}
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>