Skip to content

Commit

Permalink
Fixes #9653 - Add default_platform to DeviceType
Browse files Browse the repository at this point in the history
  • Loading branch information
kkthxbye-code authored and jeremystretch committed Feb 20, 2023
1 parent a1c9f7a commit 81b8046
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 13 deletions.
3 changes: 2 additions & 1 deletion netbox/dcim/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ class Meta:
class DeviceTypeSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail')
manufacturer = NestedManufacturerSerializer()
default_platform = NestedPlatformSerializer(required=False, allow_null=True)
u_height = serializers.DecimalField(
max_digits=4,
decimal_places=1,
Expand All @@ -324,7 +325,7 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
class Meta:
model = DeviceType
fields = [
'id', 'url', 'display', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
'id', 'url', 'display', 'manufacturer', 'default_platform', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image', 'description',
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
]
Expand Down
10 changes: 10 additions & 0 deletions netbox/dcim/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,16 @@ class DeviceTypeFilterSet(NetBoxModelFilterSet):
to_field_name='slug',
label=_('Manufacturer (slug)'),
)
default_platform_id = django_filters.ModelMultipleChoiceFilter(
queryset=Platform.objects.all(),
label=_('Default platform (ID)'),
)
default_platform = django_filters.ModelMultipleChoiceFilter(
field_name='default_platform__slug',
queryset=Platform.objects.all(),
to_field_name='slug',
label=_('Default platform (slug)'),
)
has_front_image = django_filters.BooleanFilter(
label=_('Has a front image'),
method='_has_front_image'
Expand Down
6 changes: 5 additions & 1 deletion netbox/dcim/forms/bulk_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm):
queryset=Manufacturer.objects.all(),
required=False
)
default_platform = DynamicModelChoiceField(
queryset=Platform.objects.all(),
required=False
)
part_number = forms.CharField(
required=False
)
Expand Down Expand Up @@ -412,7 +416,7 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm):

model = DeviceType
fieldsets = (
('Device Type', ('manufacturer', 'part_number', 'u_height', 'is_full_depth', 'airflow', 'description')),
('Device Type', ('manufacturer', 'default_platform', 'part_number', 'u_height', 'is_full_depth', 'airflow', 'description')),
('Weight', ('weight', 'weight_unit')),
)
nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit', 'description', 'comments')
Expand Down
9 changes: 7 additions & 2 deletions netbox/dcim/forms/bulk_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,17 @@ class DeviceTypeImportForm(NetBoxModelImportForm):
queryset=Manufacturer.objects.all(),
to_field_name='name'
)
default_platform = forms.ModelChoiceField(
queryset=Platform.objects.all(),
to_field_name='name',
required=False,
)

class Meta:
model = DeviceType
fields = [
'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
'description', 'comments',
'manufacturer', 'default_platform', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
'subdevice_role', 'airflow', 'description', 'comments',
]


Expand Down
7 changes: 6 additions & 1 deletion netbox/dcim/forms/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
model = DeviceType
fieldsets = (
(None, ('q', 'filter_id', 'tag')),
('Hardware', ('manufacturer_id', 'part_number', 'subdevice_role', 'airflow')),
('Hardware', ('manufacturer_id', 'default_platform_id', 'part_number', 'subdevice_role', 'airflow')),
('Images', ('has_front_image', 'has_rear_image')),
('Components', (
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
Expand All @@ -391,6 +391,11 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
required=False,
label=_('Manufacturer')
)
default_platform_id = DynamicModelMultipleChoiceField(
queryset=Platform.objects.all(),
required=False,
label=_('Default platform')
)
part_number = forms.CharField(
required=False
)
Expand Down
8 changes: 6 additions & 2 deletions netbox/dcim/forms/model_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,13 +378,17 @@ class DeviceTypeForm(NetBoxModelForm):
manufacturer = DynamicModelChoiceField(
queryset=Manufacturer.objects.all()
)
default_platform = DynamicModelChoiceField(
queryset=Platform.objects.all(),
required=False
)
slug = SlugField(
slug_source='model'
)
comments = CommentField()

fieldsets = (
('Device Type', ('manufacturer', 'model', 'slug', 'description', 'tags')),
('Device Type', ('manufacturer', 'model', 'slug', 'description', 'tags', 'default_platform')),
('Chassis', (
'u_height', 'is_full_depth', 'part_number', 'subdevice_role', 'airflow', 'weight', 'weight_unit',
)),
Expand All @@ -395,7 +399,7 @@ class Meta:
model = DeviceType
fields = [
'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
'weight', 'weight_unit', 'front_image', 'rear_image', 'description', 'comments', 'tags',
'weight', 'weight_unit', 'front_image', 'rear_image', 'description', 'comments', 'tags', 'default_platform'
]
widgets = {
'airflow': StaticSelect(),
Expand Down
19 changes: 19 additions & 0 deletions netbox/dcim/migrations/0169_devicetype_default_platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.1.6 on 2023-02-10 18:06

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('dcim', '0168_interface_template_enabled'),
]

operations = [
migrations.AddField(
model_name='devicetype',
name='default_platform',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.platform'),
),
]
15 changes: 14 additions & 1 deletion netbox/dcim/models/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ class DeviceType(PrimaryModel, WeightMixin):
slug = models.SlugField(
max_length=100
)
default_platform = models.ForeignKey(
to='dcim.Platform',
on_delete=models.SET_NULL,
related_name='+',
blank=True,
null=True,
verbose_name='Default platform'
)
part_number = models.CharField(
max_length=50,
blank=True,
Expand Down Expand Up @@ -121,7 +129,7 @@ class DeviceType(PrimaryModel, WeightMixin):
)

clone_fields = (
'manufacturer', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit'
'manufacturer', 'default_platform', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit'
)
prerequisite_models = (
'dcim.Manufacturer',
Expand Down Expand Up @@ -165,6 +173,7 @@ def to_yaml(self):
'manufacturer': self.manufacturer.name,
'model': self.model,
'slug': self.slug,
'default_platform': self.default_platform.name if self.default_platform else None,
'part_number': self.part_number,
'u_height': float(self.u_height),
'is_full_depth': self.is_full_depth,
Expand Down Expand Up @@ -801,6 +810,10 @@ def save(self, *args, **kwargs):
if is_new and not self.airflow:
self.airflow = self.device_type.airflow

# Inherit default_platform from DeviceType if not set
if is_new and not self.platform:
self.platform = self.device_type.default_platform

super().save(*args, **kwargs)

# If this is a new Device, instantiate all the related components per the DeviceType definition
Expand Down
5 changes: 4 additions & 1 deletion netbox/dcim/tables/devicetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ class DeviceTypeTable(NetBoxTable):
manufacturer = tables.Column(
linkify=True
)
default_platform = tables.Column(
linkify=True
)
is_full_depth = columns.BooleanColumn(
verbose_name='Full Depth'
)
Expand All @@ -100,7 +103,7 @@ class DeviceTypeTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = models.DeviceType
fields = (
'pk', 'id', 'model', 'manufacturer', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role',
'pk', 'id', 'model', 'manufacturer', 'default_platform', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role',
'airflow', 'weight', 'description', 'comments', 'instance_count', 'tags', 'created', 'last_updated',
)
default_columns = (
Expand Down
18 changes: 16 additions & 2 deletions netbox/dcim/tests/test_filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -699,9 +699,16 @@ def setUpTestData(cls):
)
Manufacturer.objects.bulk_create(manufacturers)

platforms = (
Platform(name='Platform 1', slug='platform-1', manufacturer=manufacturers[0]),
Platform(name='Platform 2', slug='platform-2', manufacturer=manufacturers[1]),
Platform(name='Platform 3', slug='platform-3', manufacturer=manufacturers[2]),
)
Platform.objects.bulk_create(platforms)

device_types = (
DeviceType(manufacturer=manufacturers[0], model='Model 1', slug='model-1', part_number='Part Number 1', u_height=1, is_full_depth=True, front_image='front.png', rear_image='rear.png', weight=10, weight_unit=WeightUnitChoices.UNIT_POUND),
DeviceType(manufacturer=manufacturers[1], model='Model 2', slug='model-2', part_number='Part Number 2', u_height=2, is_full_depth=True, subdevice_role=SubdeviceRoleChoices.ROLE_PARENT, airflow=DeviceAirflowChoices.AIRFLOW_FRONT_TO_REAR, weight=20, weight_unit=WeightUnitChoices.UNIT_POUND),
DeviceType(manufacturer=manufacturers[0], default_platform=platforms[0], model='Model 1', slug='model-1', part_number='Part Number 1', u_height=1, is_full_depth=True, front_image='front.png', rear_image='rear.png', weight=10, weight_unit=WeightUnitChoices.UNIT_POUND),
DeviceType(manufacturer=manufacturers[1], default_platform=platforms[1], model='Model 2', slug='model-2', part_number='Part Number 2', u_height=2, is_full_depth=True, subdevice_role=SubdeviceRoleChoices.ROLE_PARENT, airflow=DeviceAirflowChoices.AIRFLOW_FRONT_TO_REAR, weight=20, weight_unit=WeightUnitChoices.UNIT_POUND),
DeviceType(manufacturer=manufacturers[2], model='Model 3', slug='model-3', part_number='Part Number 3', u_height=3, is_full_depth=False, subdevice_role=SubdeviceRoleChoices.ROLE_CHILD, airflow=DeviceAirflowChoices.AIRFLOW_REAR_TO_FRONT, weight=30, weight_unit=WeightUnitChoices.UNIT_KILOGRAM),
)
DeviceType.objects.bulk_create(device_types)
Expand Down Expand Up @@ -785,6 +792,13 @@ def test_manufacturer(self):
params = {'manufacturer': [manufacturers[0].slug, manufacturers[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

def test_default_platform(self):
platforms = Platform.objects.all()[:2]
params = {'default_platform_id': [platforms[0].pk, platforms[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'default_platform': [platforms[0].slug, platforms[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

def test_has_front_image(self):
params = {'has_front_image': True}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
Expand Down
17 changes: 15 additions & 2 deletions netbox/dcim/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,12 @@ def setUpTestData(cls):
)
Manufacturer.objects.bulk_create(manufacturers)

platforms = (
Platform(name='Platform 1', slug='platform-1', manufacturer=manufacturers[0]),
Platform(name='Platform 2', slug='platform-3', manufacturer=manufacturers[1]),
)
Platform.objects.bulk_create(platforms)

DeviceType.objects.bulk_create([
DeviceType(model='Device Type 1', slug='device-type-1', manufacturer=manufacturers[0]),
DeviceType(model='Device Type 2', slug='device-type-2', manufacturer=manufacturers[0]),
Expand All @@ -513,6 +519,7 @@ def setUpTestData(cls):

cls.form_data = {
'manufacturer': manufacturers[1].pk,
'default_platform': platforms[0].pk,
'model': 'Device Type X',
'slug': 'device-type-x',
'part_number': '123ABC',
Expand All @@ -525,6 +532,7 @@ def setUpTestData(cls):

cls.bulk_edit_data = {
'manufacturer': manufacturers[1].pk,
'default_platform': platforms[1].pk,
'u_height': 3,
'is_full_depth': False,
}
Expand Down Expand Up @@ -673,6 +681,7 @@ def test_import_objects(self):
"""
IMPORT_DATA = """
manufacturer: Generic
default_platform: Platform
model: TEST-1000
slug: test-1000
u_height: 2
Expand Down Expand Up @@ -755,8 +764,11 @@ def test_import_objects(self):
manufacturer: Generic
"""

# Create the manufacturer
Manufacturer(name='Generic', slug='generic').save()
# Create the manufacturer and platform
manufacturer = Manufacturer(name='Generic', slug='generic')
manufacturer.save()
platform = Platform(name='Platform', slug='test-platform', manufacturer=manufacturer)
platform.save()

# Add all required permissions to the test user
self.add_permissions(
Expand All @@ -783,6 +795,7 @@ def test_import_objects(self):

device_type = DeviceType.objects.get(model='TEST-1000')
self.assertEqual(device_type.comments, 'Test comment')
self.assertEqual(device_type.default_platform.pk, platform.pk)

# Verify all of the components were created
self.assertEqual(device_type.consoleporttemplates.count(), 3)
Expand Down
4 changes: 4 additions & 0 deletions netbox/templates/dcim/devicetype.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ <h5 class="card-header">
<td>Part Number</td>
<td>{{ object.part_number|placeholder }}</td>
</tr>
<tr>
<td>Default Platform</td>
<td>{{ object.default_platform|linkify }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ object.description|placeholder }}</td>
Expand Down

0 comments on commit 81b8046

Please sign in to comment.