diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 283382515..13781a696 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -119,7 +119,7 @@ class RackSerializer(TaggitSerializer, CustomFieldModelSerializer): role = NestedRackRoleSerializer(required=False, allow_null=True) type = ChoiceField(choices=RackTypeChoices, required=False, allow_null=True) width = ChoiceField(choices=RackWidthChoices, required=False) - outer_unit = ChoiceField(choices=RACK_DIMENSION_UNIT_CHOICES, required=False) + outer_unit = ChoiceField(choices=RackDimensionUnitChoices, required=False) tags = TagListSerializerField(required=False) device_count = serializers.IntegerField(read_only=True) powerfeed_count = serializers.IntegerField(read_only=True) diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index d9e02ab4f..2ffb30b38 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -89,6 +89,22 @@ class RackStatusChoices(ChoiceSet): } +class RackDimensionUnitChoices(ChoiceSet): + + UNIT_MILLIMETER = 'mm' + UNIT_INCH = 'in' + + CHOICES = ( + (UNIT_MILLIMETER, 'Millimeters'), + (UNIT_INCH, 'Inches'), + ) + + LEGACY_MAP = { + UNIT_MILLIMETER: 1000, + UNIT_INCH: 2000, + } + + # # DeviceTypes # diff --git a/netbox/dcim/constants.py b/netbox/dcim/constants.py index d2b715415..4aca9a2a1 100644 --- a/netbox/dcim/constants.py +++ b/netbox/dcim/constants.py @@ -67,16 +67,6 @@ COMPATIBLE_TERMINATION_TYPES = { 'circuittermination': ['interface', 'frontport', 'rearport'], } -LENGTH_UNIT_METER = 1200 -LENGTH_UNIT_CENTIMETER = 1100 -LENGTH_UNIT_MILLIMETER = 1000 -LENGTH_UNIT_FOOT = 2100 -LENGTH_UNIT_INCH = 2000 -RACK_DIMENSION_UNIT_CHOICES = ( - (LENGTH_UNIT_MILLIMETER, 'Millimeters'), - (LENGTH_UNIT_INCH, 'Inches'), -) - # Power feeds POWERFEED_TYPE_PRIMARY = 1 POWERFEED_TYPE_REDUNDANT = 2 diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index c606c4797..bf34c7971 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -496,7 +496,7 @@ class RackCSVForm(forms.ModelForm): help_text='Rail-to-rail width (in inches)' ) outer_unit = CSVChoiceField( - choices=RACK_DIMENSION_UNIT_CHOICES, + choices=RackDimensionUnitChoices, required=False, help_text='Unit for outer dimensions' ) @@ -617,7 +617,7 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor min_value=1 ) outer_unit = forms.ChoiceField( - choices=add_blank_choice(RACK_DIMENSION_UNIT_CHOICES), + choices=add_blank_choice(RackDimensionUnitChoices), required=False, widget=StaticSelect2() ) diff --git a/netbox/dcim/migrations/0079_3569_rack_fields.py b/netbox/dcim/migrations/0079_3569_rack_fields.py index 137cd6fe5..a33b83eb7 100644 --- a/netbox/dcim/migrations/0079_3569_rack_fields.py +++ b/netbox/dcim/migrations/0079_3569_rack_fields.py @@ -16,6 +16,11 @@ RACK_STATUS_CHOICES = ( (4, 'deprecated'), ) +RACK_DIMENSION_CHOICES = ( + (1000, 'mm'), + (2000, 'in'), +) + def rack_type_to_slug(apps, schema_editor): Rack = apps.get_model('dcim', 'Rack') @@ -29,6 +34,12 @@ def rack_status_to_slug(apps, schema_editor): Rack.objects.filter(status=str(id)).update(status=slug) +def rack_outer_unit_to_slug(apps, schema_editor): + Rack = apps.get_model('dcim', 'Rack') + for id, slug in RACK_DIMENSION_CHOICES: + Rack.objects.filter(status=str(id)).update(status=slug) + + class Migration(migrations.Migration): atomic = False @@ -62,4 +73,19 @@ class Migration(migrations.Migration): migrations.RunPython( code=rack_status_to_slug ), + + # Rack.outer_unit + migrations.AlterField( + model_name='rack', + name='outer_unit', + field=models.CharField(blank=True, default='', max_length=50), + ), + migrations.RunPython( + code=rack_outer_unit_to_slug + ), + migrations.AlterField( + model_name='rack', + name='outer_unit', + field=models.CharField(blank=True, max_length=50), + ), ] diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 52b55373d..6d8748313 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -535,10 +535,10 @@ class Rack(ChangeLoggedModel, CustomFieldModel): blank=True, null=True ) - outer_unit = models.PositiveSmallIntegerField( - choices=RACK_DIMENSION_UNIT_CHOICES, + outer_unit = models.CharField( + max_length=50, + choices=RackDimensionUnitChoices, blank=True, - null=True ) comments = models.TextField( blank=True @@ -584,10 +584,10 @@ class Rack(ChangeLoggedModel, CustomFieldModel): def clean(self): # Validate outer dimensions and unit - if (self.outer_width is not None or self.outer_depth is not None) and self.outer_unit is None: + if (self.outer_width is not None or self.outer_depth is not None) and not self.outer_unit: raise ValidationError("Must specify a unit when setting an outer width/depth") elif self.outer_width is None and self.outer_depth is None: - self.outer_unit = None + self.outer_unit = '' if self.pk: # Validate that Rack is tall enough to house the installed Devices diff --git a/netbox/utilities/utils.py b/netbox/utilities/utils.py index 011d9e85f..3720fd76d 100644 --- a/netbox/utilities/utils.py +++ b/netbox/utilities/utils.py @@ -5,7 +5,7 @@ from collections import OrderedDict from django.core.serializers import serialize from django.db.models import Count, OuterRef, Subquery -from dcim.constants import LENGTH_UNIT_CENTIMETER, LENGTH_UNIT_FOOT, LENGTH_UNIT_INCH, LENGTH_UNIT_METER +from dcim.choices import CableLengthUnitChoices def csv_format(data): @@ -165,12 +165,18 @@ def to_meters(length, unit): length = int(length) if length < 0: raise ValueError("Length must be a positive integer") - if unit == LENGTH_UNIT_METER: + + valid_units = [u[0] for u in CableLengthUnitChoices] + if unit not in valid_units: + raise ValueError( + "Unknown unit {}. Must be one of the following: {}".format(unit, ', '.join(valid_units)) + ) + + if unit == CableLengthUnitChoices.UNIT_METER: return length - if unit == LENGTH_UNIT_CENTIMETER: + if unit == CableLengthUnitChoices.UNIT_CENTIMETER: return length / 100 - if unit == LENGTH_UNIT_FOOT: + if unit == CableLengthUnitChoices.UNIT_FOOT: return length * 0.3048 - if unit == LENGTH_UNIT_INCH: + if unit == CableLengthUnitChoices.UNIT_INCH: return length * 0.3048 * 12 - raise ValueError("Unknown unit {}. Must be 'm', 'cm', 'ft', or 'in'.".format(unit))