18417 Add outer_height to racks (#18940)

* 18417 add rack outer height

* 18417 add rack outer height

* 18417 fix tests

* 18417 fix validation message

* Update netbox/dcim/filtersets.py

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>

* Update netbox/dcim/filtersets.py

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>

* Update netbox/dcim/models/racks.py

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>

* Update netbox/dcim/models/racks.py

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>

* Update netbox/dcim/models/racks.py

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>

* Update netbox/dcim/models/racks.py

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>

* 16224 review changes

* 16224 review changes

* 16224 update table display

* 18417 use TemplateColumn

* 18417 review changes

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
Arthur Hanson 2025-03-26 05:42:13 -07:00 committed by GitHub
parent fe7cc8cae9
commit 7a71c7b8f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 128 additions and 49 deletions

View File

@ -40,7 +40,7 @@ The number of the numerically lowest unit in the rack. This value defaults to on
### Outer Dimensions ### Outer Dimensions
The external width and depth of the rack can be tracked to aid in floorplan calculations. These measurements must be designated in either millimeters or inches. The external width, height and depth of the rack can be tracked to aid in floorplan calculations. These measurements must be designated in either millimeters or inches.
### Mounting Depth ### Mounting Depth

View File

@ -70,8 +70,8 @@ class RackTypeSerializer(RackBaseSerializer):
model = RackType model = RackType
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'manufacturer', 'model', 'slug', 'description', 'form_factor', 'id', 'url', 'display_url', 'display', 'manufacturer', 'model', 'slug', 'description', 'form_factor',
'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'weight', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_height', 'outer_depth',
'max_weight', 'weight_unit', 'mounting_depth', 'description', 'comments', 'tags', 'outer_unit', 'weight', 'max_weight', 'weight_unit', 'mounting_depth', 'description', 'comments', 'tags',
'custom_fields', 'created', 'last_updated', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description') brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description')
@ -129,9 +129,9 @@ class RackSerializer(RackBaseSerializer):
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', 'id', 'url', 'display_url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status',
'role', 'serial', 'asset_tag', 'rack_type', 'form_factor', 'width', 'u_height', 'starting_unit', 'weight', 'role', 'serial', 'asset_tag', 'rack_type', 'form_factor', 'width', 'u_height', 'starting_unit', 'weight',
'max_weight', 'weight_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'max_weight', 'weight_unit', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit',
'airflow', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'mounting_depth', 'airflow', 'description', 'comments', 'tags', 'custom_fields',
'powerfeed_count', 'created', 'last_updated', 'device_count', 'powerfeed_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description', 'device_count') brief_fields = ('id', 'url', 'display', 'name', 'description', 'device_count')

View File

@ -313,8 +313,8 @@ class RackTypeFilterSet(NetBoxModelFilterSet):
class Meta: class Meta:
model = RackType model = RackType
fields = ( fields = (
'id', 'model', 'slug', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', 'id', 'model', 'slug', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_height',
'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description',
) )
def search(self, queryset, name, value): def search(self, queryset, name, value):
@ -426,8 +426,8 @@ class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe
model = Rack model = Rack
fields = ( fields = (
'id', 'name', 'facility_id', 'asset_tag', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'id', 'name', 'facility_id', 'asset_tag', 'u_height', 'starting_unit', 'desc_units', 'outer_width',
'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'weight_unit', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight',
'description', 'weight_unit', 'description',
) )
def search(self, queryset, name, value): def search(self, queryset, name, value):

View File

@ -260,6 +260,11 @@ class RackTypeBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
min_value=1 min_value=1
) )
outer_height = forms.IntegerField(
label=_('Outer height'),
required=False,
min_value=1
)
outer_depth = forms.IntegerField( outer_depth = forms.IntegerField(
label=_('Outer depth'), label=_('Outer depth'),
required=False, required=False,
@ -302,7 +307,7 @@ class RackTypeBulkEditForm(NetBoxModelBulkEditForm):
fieldsets = ( fieldsets = (
FieldSet('manufacturer', 'description', 'form_factor', 'width', 'u_height', name=_('Rack Type')), FieldSet('manufacturer', 'description', 'form_factor', 'width', 'u_height', name=_('Rack Type')),
FieldSet( FieldSet(
InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), InlineFields('outer_width', 'outer_height', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')),
InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')), InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')),
'mounting_depth', 'mounting_depth',
name=_('Dimensions') name=_('Dimensions')
@ -310,7 +315,7 @@ class RackTypeBulkEditForm(NetBoxModelBulkEditForm):
FieldSet('starting_unit', 'desc_units', name=_('Numbering')), FieldSet('starting_unit', 'desc_units', name=_('Numbering')),
) )
nullable_fields = ( nullable_fields = (
'outer_width', 'outer_depth', 'outer_unit', 'weight', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'weight',
'max_weight', 'weight_unit', 'description', 'comments', 'max_weight', 'weight_unit', 'description', 'comments',
) )
@ -404,6 +409,11 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
min_value=1 min_value=1
) )
outer_height = forms.IntegerField(
label=_('Outer height'),
required=False,
min_value=1
)
outer_depth = forms.IntegerField( outer_depth = forms.IntegerField(
label=_('Outer depth'), label=_('Outer depth'),
required=False, required=False,
@ -451,15 +461,13 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
fieldsets = ( fieldsets = (
FieldSet('status', 'role', 'tenant', 'serial', 'asset_tag', 'rack_type', 'description', name=_('Rack')), FieldSet('status', 'role', 'tenant', 'serial', 'asset_tag', 'rack_type', 'description', name=_('Rack')),
FieldSet('region', 'site_group', 'site', 'location', name=_('Location')), FieldSet('region', 'site_group', 'site', 'location', name=_('Location')),
FieldSet( FieldSet('outer_width', 'outer_height', 'outer_depth', 'outer_unit', name=_('Outer Dimensions')),
'form_factor', 'width', 'u_height', 'desc_units', 'airflow', 'outer_width', 'outer_depth', 'outer_unit', FieldSet('form_factor', 'width', 'u_height', 'desc_units', 'airflow', 'mounting_depth', name=_('Hardware')),
'mounting_depth', name=_('Hardware')
),
FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')), FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
) )
nullable_fields = ( nullable_fields = (
'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'weight', 'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_height', 'outer_depth',
'max_weight', 'weight_unit', 'description', 'comments', 'outer_unit', 'weight', 'max_weight', 'weight_unit', 'description', 'comments',
) )

View File

@ -222,7 +222,7 @@ class RackTypeImportForm(NetBoxModelImportForm):
model = RackType model = RackType
fields = ( fields = (
'manufacturer', 'model', 'slug', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'manufacturer', 'model', 'slug', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units',
'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight',
'weight_unit', 'description', 'comments', 'tags', 'weight_unit', 'description', 'comments', 'tags',
) )
@ -307,7 +307,7 @@ class RackImportForm(NetBoxModelImportForm):
model = Rack model = Rack
fields = ( fields = (
'site', 'location', 'name', 'facility_id', 'tenant', 'status', 'role', 'rack_type', 'form_factor', 'serial', 'site', 'location', 'name', 'facility_id', 'tenant', 'status', 'role', 'rack_type', 'form_factor', 'serial',
'asset_tag', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'asset_tag', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit',
'mounting_depth', 'airflow', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags',
) )

View File

@ -226,7 +226,7 @@ class RackTypeForm(NetBoxModelForm):
FieldSet('manufacturer', 'model', 'slug', 'description', 'form_factor', 'tags', name=_('Rack Type')), FieldSet('manufacturer', 'model', 'slug', 'description', 'form_factor', 'tags', name=_('Rack Type')),
FieldSet( FieldSet(
'width', 'u_height', 'width', 'u_height',
InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), InlineFields('outer_width', 'outer_height', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')),
InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')), InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')),
'mounting_depth', name=_('Dimensions') 'mounting_depth', name=_('Dimensions')
), ),
@ -237,8 +237,8 @@ class RackTypeForm(NetBoxModelForm):
model = RackType model = RackType
fields = [ fields = [
'manufacturer', 'model', 'slug', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'manufacturer', 'model', 'slug', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units',
'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight',
'description', 'comments', 'tags', 'weight_unit', 'description', 'comments', 'tags',
] ]
@ -283,8 +283,8 @@ class RackForm(TenancyForm, NetBoxModelForm):
fields = [ fields = [
'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial', 'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial',
'asset_tag', 'rack_type', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'asset_tag', 'rack_type', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width',
'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'weight_unit', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight',
'description', 'comments', 'tags', 'weight_unit', 'description', 'comments', 'tags',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -306,7 +306,8 @@ class RackForm(TenancyForm, NetBoxModelForm):
*self.fieldsets, *self.fieldsets,
FieldSet( FieldSet(
'form_factor', 'width', 'starting_unit', 'u_height', 'form_factor', 'width', 'starting_unit', 'u_height',
InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), InlineFields('outer_width', 'outer_height', 'outer_depth', 'outer_unit',
label=_('Outer Dimensions')),
InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')), InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')),
'mounting_depth', 'desc_units', name=_('Dimensions') 'mounting_depth', 'desc_units', name=_('Dimensions')
), ),

View File

@ -0,0 +1,23 @@
# Generated by Django 5.2b1 on 2025-03-18 15:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dcim', '0202_location_comments_region_comments_sitegroup_comments'),
]
operations = [
migrations.AddField(
model_name='rack',
name='outer_height',
field=models.PositiveSmallIntegerField(blank=True, null=True),
),
migrations.AddField(
model_name='racktype',
name='outer_height',
field=models.PositiveSmallIntegerField(blank=True, null=True),
),
]

View File

@ -73,6 +73,12 @@ class RackBase(WeightMixin, PrimaryModel):
null=True, null=True,
help_text=_('Outer dimension of rack (width)') help_text=_('Outer dimension of rack (width)')
) )
outer_height = models.PositiveSmallIntegerField(
verbose_name=_('outer height'),
blank=True,
null=True,
help_text=_('Outer dimension of rack (height)')
)
outer_depth = models.PositiveSmallIntegerField( outer_depth = models.PositiveSmallIntegerField(
verbose_name=_('outer depth'), verbose_name=_('outer depth'),
blank=True, blank=True,
@ -140,7 +146,7 @@ class RackType(RackBase):
) )
clone_fields = ( clone_fields = (
'manufacturer', 'form_factor', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'manufacturer', 'form_factor', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_height', 'outer_depth',
'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit',
) )
prerequisite_models = ( prerequisite_models = (
@ -173,8 +179,8 @@ class RackType(RackBase):
super().clean() super().clean()
# Validate outer dimensions and unit # Validate outer dimensions and unit
if (self.outer_width is not None or self.outer_depth is not None) and not self.outer_unit: if any([self.outer_width, self.outer_depth, self.outer_height]) and not self.outer_unit:
raise ValidationError(_("Must specify a unit when setting an outer width/depth")) raise ValidationError(_("Must specify a unit when setting an outer dimension"))
# Validate max_weight and weight_unit # Validate max_weight and weight_unit
if self.max_weight and not self.weight_unit: if self.max_weight and not self.weight_unit:
@ -188,7 +194,7 @@ class RackType(RackBase):
self._abs_max_weight = None self._abs_max_weight = None
# Clear unit if outer width & depth are not set # Clear unit if outer width & depth are not set
if self.outer_width is None and self.outer_depth is None: if not any([self.outer_width, self.outer_depth, self.outer_height]):
self.outer_unit = None self.outer_unit = None
super().save(*args, **kwargs) super().save(*args, **kwargs)
@ -235,8 +241,8 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase):
""" """
# Fields which cannot be set locally if a RackType is assigned # Fields which cannot be set locally if a RackType is assigned
RACKTYPE_FIELDS = ( RACKTYPE_FIELDS = (
'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_height',
'outer_unit', 'mounting_depth', 'weight', 'weight_unit', 'max_weight', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'weight_unit', 'max_weight',
) )
form_factor = models.CharField( form_factor = models.CharField(
@ -329,7 +335,8 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase):
clone_fields = ( clone_fields = (
'site', 'location', 'tenant', 'status', 'role', 'form_factor', 'width', 'airflow', 'u_height', 'desc_units', 'site', 'location', 'tenant', 'status', 'role', 'form_factor', 'width', 'airflow', 'u_height', 'desc_units',
'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight',
'weight_unit',
) )
prerequisite_models = ( prerequisite_models = (
'dcim.Site', 'dcim.Site',
@ -364,8 +371,8 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase):
raise ValidationError(_("Assigned location must belong to parent site ({site}).").format(site=self.site)) raise ValidationError(_("Assigned location must belong to parent site ({site}).").format(site=self.site))
# Validate outer dimensions and unit # Validate outer dimensions and unit
if (self.outer_width is not None or self.outer_depth is not None) and not self.outer_unit: if any([self.outer_width, self.outer_depth, self.outer_height]) and not self.outer_unit:
raise ValidationError(_("Must specify a unit when setting an outer width/depth")) raise ValidationError(_("Must specify a unit when setting an outer dimension"))
# Validate max_weight and weight_unit # Validate max_weight and weight_unit
if self.max_weight and not self.weight_unit: if self.max_weight and not self.weight_unit:
@ -414,7 +421,7 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase):
self._abs_max_weight = None self._abs_max_weight = None
# Clear unit if outer width & depth are not set # Clear unit if outer width & depth are not set
if self.outer_width is None and self.outer_depth is None: if not any([self.outer_width, self.outer_depth, self.outer_height]):
self.outer_unit = None self.outer_unit = None
super().save(*args, **kwargs) super().save(*args, **kwargs)

View File

@ -5,7 +5,7 @@ from django_tables2.utils import Accessor
from dcim.models import Rack, RackReservation, RackRole, RackType from dcim.models import Rack, RackReservation, RackRole, RackType
from netbox.tables import NetBoxTable, columns from netbox.tables import NetBoxTable, columns
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from .template_code import WEIGHT from .template_code import OUTER_UNIT, WEIGHT
__all__ = ( __all__ = (
'RackTable', 'RackTable',
@ -62,12 +62,16 @@ class RackTypeTable(NetBoxTable):
template_code="{{ value }}U", template_code="{{ value }}U",
verbose_name=_('Height') verbose_name=_('Height')
) )
outer_width = tables.TemplateColumn( outer_width = columns.TemplateColumn(
template_code="{{ record.outer_width }} {{ record.outer_unit }}", template_code=OUTER_UNIT,
verbose_name=_('Outer Width') verbose_name=_('Outer Width')
) )
outer_depth = tables.TemplateColumn( outer_height = columns.TemplateColumn(
template_code="{{ record.outer_depth }} {{ record.outer_unit }}", template_code=OUTER_UNIT,
verbose_name=_('Outer Height')
)
outer_depth = columns.TemplateColumn(
template_code=OUTER_UNIT,
verbose_name=_('Outer Depth') verbose_name=_('Outer Depth')
) )
weight = columns.TemplateColumn( weight = columns.TemplateColumn(
@ -96,8 +100,8 @@ class RackTypeTable(NetBoxTable):
model = RackType model = RackType
fields = ( fields = (
'pk', 'id', 'model', 'manufacturer', 'form_factor', 'u_height', 'starting_unit', 'width', 'outer_width', 'pk', 'id', 'model', 'manufacturer', 'form_factor', 'u_height', 'starting_unit', 'width', 'outer_width',
'outer_depth', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'description', 'comments', 'outer_height', 'outer_depth', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'description',
'instance_count', 'tags', 'created', 'last_updated', 'comments', 'instance_count', 'tags', 'created', 'last_updated',
) )
default_columns = ( default_columns = (
'pk', 'model', 'manufacturer', 'type', 'u_height', 'description', 'instance_count', 'pk', 'model', 'manufacturer', 'type', 'u_height', 'description', 'instance_count',
@ -159,12 +163,16 @@ class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:rack_list' url_name='dcim:rack_list'
) )
outer_width = tables.TemplateColumn( outer_width = columns.TemplateColumn(
template_code="{{ record.outer_width }} {{ record.outer_unit }}", template_code=OUTER_UNIT,
verbose_name=_('Outer Width') verbose_name=_('Outer Width')
) )
outer_depth = tables.TemplateColumn( outer_height = columns.TemplateColumn(
template_code="{{ record.outer_depth }} {{ record.outer_unit }}", template_code=OUTER_UNIT,
verbose_name=_('Outer Height')
)
outer_depth = columns.TemplateColumn(
template_code=OUTER_UNIT,
verbose_name=_('Outer Depth') verbose_name=_('Outer Depth')
) )
weight = columns.TemplateColumn( weight = columns.TemplateColumn(
@ -183,8 +191,9 @@ class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
fields = ( fields = (
'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'tenant_group', 'role', 'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'tenant_group', 'role',
'rack_type', 'serial', 'asset_tag', 'form_factor', 'u_height', 'starting_unit', 'width', 'outer_width', 'rack_type', 'serial', 'asset_tag', 'form_factor', 'u_height', 'starting_unit', 'width', 'outer_width',
'outer_depth', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'comments', 'device_count', 'outer_height', 'outer_depth', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'comments',
'get_utilization', 'get_power_utilization', 'description', 'contacts', 'tags', 'created', 'last_updated', 'device_count', 'get_utilization', 'get_power_utilization', 'description', 'contacts',
'tags', 'created', 'last_updated',
) )
default_columns = ( default_columns = (
'pk', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'rack_type', 'u_height', 'pk', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'rack_type', 'u_height',

View File

@ -109,6 +109,11 @@ LOCATION_BUTTONS = """
</a> </a>
""" """
OUTER_UNIT = """
{% load helpers %}
{% if value %}{{ value }} {{ record.outer_unit }}{% endif %}
"""
# #
# Device component templatebuttons # Device component templatebuttons
# #

View File

@ -585,6 +585,7 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
starting_unit=1, starting_unit=1,
desc_units=False, desc_units=False,
outer_width=100, outer_width=100,
outer_height=100,
outer_depth=100, outer_depth=100,
outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
mounting_depth=100, mounting_depth=100,
@ -603,6 +604,7 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
starting_unit=2, starting_unit=2,
desc_units=False, desc_units=False,
outer_width=200, outer_width=200,
outer_height=200,
outer_depth=200, outer_depth=200,
outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
mounting_depth=200, mounting_depth=200,
@ -621,6 +623,7 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
starting_unit=3, starting_unit=3,
desc_units=True, desc_units=True,
outer_width=300, outer_width=300,
outer_height=300,
outer_depth=300, outer_depth=300,
outer_unit=RackDimensionUnitChoices.UNIT_INCH, outer_unit=RackDimensionUnitChoices.UNIT_INCH,
mounting_depth=300, mounting_depth=300,
@ -681,6 +684,10 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'outer_width': [100, 200]} params = {'outer_width': [100, 200]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_outer_height(self):
params = {'outer_height': [100, 200]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_outer_depth(self): def test_outer_depth(self):
params = {'outer_depth': [100, 200]} params = {'outer_depth': [100, 200]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -764,6 +771,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
starting_unit=1, starting_unit=1,
desc_units=False, desc_units=False,
outer_width=100, outer_width=100,
outer_height=100,
outer_depth=100, outer_depth=100,
outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
mounting_depth=100, mounting_depth=100,
@ -782,6 +790,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
starting_unit=2, starting_unit=2,
desc_units=False, desc_units=False,
outer_width=200, outer_width=200,
outer_height=200,
outer_depth=200, outer_depth=200,
outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
mounting_depth=200, mounting_depth=200,
@ -831,6 +840,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
u_height=42, u_height=42,
desc_units=False, desc_units=False,
outer_width=100, outer_width=100,
outer_height=100,
outer_depth=100, outer_depth=100,
outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
weight=10, weight=10,
@ -854,6 +864,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
u_height=43, u_height=43,
desc_units=False, desc_units=False,
outer_width=200, outer_width=200,
outer_height=200,
outer_depth=200, outer_depth=200,
outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
weight=20, weight=20,
@ -877,6 +888,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
u_height=44, u_height=44,
desc_units=True, desc_units=True,
outer_width=300, outer_width=300,
outer_height=300,
outer_depth=300, outer_depth=300,
outer_unit=RackDimensionUnitChoices.UNIT_INCH, outer_unit=RackDimensionUnitChoices.UNIT_INCH,
weight=30, weight=30,
@ -957,6 +969,10 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'outer_width': [100, 200]} params = {'outer_width': [100, 200]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_outer_height(self):
params = {'outer_height': [100, 200]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_outer_depth(self): def test_outer_depth(self):
params = {'outer_depth': [100, 200]} params = {'outer_depth': [100, 200]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -24,6 +24,16 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
<tr>
<th scope="row">{% trans "Outer Height" %}</th>
<td>
{% if object.outer_height %}
{{ object.outer_height }} {{ object.get_outer_unit_display }}
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
</tr>
<tr> <tr>
<th scope="row">{% trans "Outer Depth" %}</th> <th scope="row">{% trans "Outer Depth" %}</th>
<td> <td>