diff --git a/netbox/dcim/api/serializers_/racks.py b/netbox/dcim/api/serializers_/racks.py index f48aabf07..74087fc5a 100644 --- a/netbox/dcim/api/serializers_/racks.py +++ b/netbox/dcim/api/serializers_/racks.py @@ -60,6 +60,7 @@ class RackSerializer(NetBoxModelSerializer): type = ChoiceField(choices=RackTypeChoices, allow_blank=True, required=False, allow_null=True) facility_id = serializers.CharField(max_length=50, allow_blank=True, allow_null=True, label=_('Facility ID'), default=None) + rack_type = RackTypeSerializer(nested=True, required=False, allow_null=True, default=None) width = ChoiceField(choices=RackWidthChoices, required=False) outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False, allow_null=True) weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True) @@ -72,9 +73,10 @@ class RackSerializer(NetBoxModelSerializer): model = Rack fields = [ 'id', 'url', 'display_url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', - 'role', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'starting_unit', 'weight', 'max_weight', - 'weight_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'description', - 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count', + 'role', 'serial', 'asset_tag', 'rack_type', 'type', 'width', 'u_height', 'starting_unit', 'weight', + 'max_weight', 'weight_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', + 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', + 'powerfeed_count', ] brief_fields = ('id', 'url', 'display', 'name', 'description', 'device_count') diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index 39c1ecb79..1e41c5daa 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -243,6 +243,11 @@ class RackForm(TenancyForm, NetBoxModelForm): queryset=RackRole.objects.all(), required=False ) + rack_type = DynamicModelChoiceField( + label=_('Rack Type'), + queryset=RackType.objects.all(), + required=False + ) comments = CommentField() fieldsets = ( @@ -250,7 +255,7 @@ class RackForm(TenancyForm, NetBoxModelForm): FieldSet('facility_id', 'serial', 'asset_tag', name=_('Inventory Control')), FieldSet('tenant_group', 'tenant', name=_('Tenancy')), FieldSet( - 'type', 'width', 'starting_unit', 'u_height', + 'rack_type', 'type', 'width', 'starting_unit', 'u_height', InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')), 'mounting_depth', 'desc_units', name=_('Dimensions') @@ -261,7 +266,7 @@ class RackForm(TenancyForm, NetBoxModelForm): model = Rack fields = [ 'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial', - 'asset_tag', 'type', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', + 'asset_tag', 'rack_type', 'type', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags', ] diff --git a/netbox/dcim/graphql/types.py b/netbox/dcim/graphql/types.py index 94f953386..14300c825 100644 --- a/netbox/dcim/graphql/types.py +++ b/netbox/dcim/graphql/types.py @@ -628,6 +628,7 @@ class RackType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObje tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None role: Annotated["RackRoleType", strawberry.lazy('dcim.graphql.types')] | None + rack_type: Annotated["RackTypeType", strawberry.lazy('dcim.graphql.types')] | None reservations: List[Annotated["RackReservationType", strawberry.lazy('dcim.graphql.types')]] devices: List[Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')]] powerfeeds: List[Annotated["PowerFeedType", strawberry.lazy('dcim.graphql.types')]] diff --git a/netbox/dcim/migrations/0188_racktype.py b/netbox/dcim/migrations/0188_racktype.py index 5a1373c35..d2563dc9b 100644 --- a/netbox/dcim/migrations/0188_racktype.py +++ b/netbox/dcim/migrations/0188_racktype.py @@ -72,4 +72,15 @@ class Migration(migrations.Migration): 'ordering': ('_name', 'pk'), }, ), + migrations.AddField( + model_name='rack', + name='rack_type', + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='instances', + to='dcim.racktype', + ), + ), ] diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index 99a5b42d4..7b6ccaecb 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -37,7 +37,7 @@ __all__ = ( # Rack Types # -class RackType(ImageAttachmentsMixin, PrimaryModel, WeightMixin): +class RackType(PrimaryModel, WeightMixin): """ Devices are housed within Racks. Each rack has a defined height measured in rack units, and a front and rear face. Each Rack is assigned to a Site and (optionally) a Location. @@ -201,6 +201,13 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, PrimaryModel, WeightMixin): Devices are housed within Racks. Each rack has a defined height measured in rack units, and a front and rear face. Each Rack is assigned to a Site and (optionally) a Location. """ + rack_type = models.ForeignKey( + to='dcim.RackType', + on_delete=models.PROTECT, + related_name='instances', + blank=True, + null=True, + ) name = models.CharField( verbose_name=_('name'), max_length=100 @@ -413,6 +420,18 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, PrimaryModel, WeightMixin): }) def save(self, *args, **kwargs): + if (not self.pk) and self.rack_type: + self.width = self.rack_type.width + self.u_height = self.rack_type.u_height + self.starting_unit = self.rack_type.starting_unit + self.desc_units = self.rack_type.desc_units + self.outer_width = self.rack_type.outer_width + self.outer_depth = self.rack_type.outer_depth + self.outer_unit = self.rack_type.outer_unit + self.weight = self.rack_type.weight + self.weight_unit = self.rack_type.weight_unit + self.max_weight = self.rack_type.max_weight + self.mounting_depth = self.rack_type.mounting_depth # Store the given max weight (if any) in grams for use in database ordering if self.max_weight and self.weight_unit: diff --git a/netbox/templates/dcim/racktype.html b/netbox/templates/dcim/racktype.html index 141aa4701..fd17b78e1 100644 --- a/netbox/templates/dcim/racktype.html +++ b/netbox/templates/dcim/racktype.html @@ -10,7 +10,7 @@
{% trans "Description" %} | @@ -100,17 +100,9 @@ {% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/tags.html' %} {% include 'inc/panels/comments.html' %} - {% include 'inc/panels/image_attachments.html' %} {% plugin_left_page object %}
---|