diff --git a/docs/models/dcim/racktype.md b/docs/models/dcim/racktype.md index 73fb08bcd..04dd63eee 100644 --- a/docs/models/dcim/racktype.md +++ b/docs/models/dcim/racktype.md @@ -10,9 +10,13 @@ A rack type defines the physical characteristics of a particular model of [rack] The [manufacturer](./manufacturer.md) which produces this type of rack. -### Name +### Model -The unique name of the rack type. +The model number assigned to this rack type by its manufacturer. Must be unique to the manufacturer. + +### Slug + +A unique URL-friendly representation of the model identifier. (This value can be used for filtering.) ### Form Factor diff --git a/netbox/dcim/api/serializers_/racks.py b/netbox/dcim/api/serializers_/racks.py index 17c1c174e..4a0fe5daa 100644 --- a/netbox/dcim/api/serializers_/racks.py +++ b/netbox/dcim/api/serializers_/racks.py @@ -73,12 +73,12 @@ class RackTypeSerializer(RackBaseSerializer): class Meta: model = RackType fields = [ - 'id', 'url', 'display_url', 'display', 'manufacturer', 'name', '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', 'max_weight', 'weight_unit', 'mounting_depth', 'airflow', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] - brief_fields = ('id', 'url', 'display', 'manufacturer', 'name', 'slug', 'description') + brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description') class RackSerializer(RackBaseSerializer): diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index 988c7fc76..255b9bd50 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -311,7 +311,7 @@ class RackTypeFilterSet(NetBoxModelFilterSet): class Meta: model = RackType fields = ( - 'id', 'name', 'slug', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', + 'id', 'model', 'slug', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'weight_unit', 'description', ) @@ -319,7 +319,7 @@ class RackTypeFilterSet(NetBoxModelFilterSet): if not value.strip(): return queryset return queryset.filter( - Q(name__icontains=value) | + Q(model__icontains=value) | Q(description__icontains=value) | Q(comments__icontains=value) ) diff --git a/netbox/dcim/forms/bulk_import.py b/netbox/dcim/forms/bulk_import.py index 785b4fb42..2e537d978 100644 --- a/netbox/dcim/forms/bulk_import.py +++ b/netbox/dcim/forms/bulk_import.py @@ -222,7 +222,7 @@ class RackTypeImportForm(NetBoxModelImportForm): class Meta: model = RackType fields = ( - 'manufacturer', 'name', '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', 'airflow', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags', ) diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index 7f7252c6e..4a9e2f25b 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -208,10 +208,13 @@ class RackTypeForm(NetBoxModelForm): queryset=Manufacturer.objects.all() ) comments = CommentField() - slug = SlugField() + slug = SlugField( + label=_('Slug'), + slug_source='model' + ) fieldsets = ( - FieldSet('manufacturer', 'name', 'slug', 'description', 'form_factor', 'airflow', 'tags', name=_('Rack Type')), + FieldSet('manufacturer', 'model', 'slug', 'description', 'form_factor', 'airflow', 'tags', name=_('Rack Type')), FieldSet( 'width', 'u_height', InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), @@ -224,7 +227,7 @@ class RackTypeForm(NetBoxModelForm): class Meta: model = RackType fields = [ - 'manufacturer', 'name', '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', 'airflow', 'description', 'comments', 'tags', ] diff --git a/netbox/dcim/graphql/types.py b/netbox/dcim/graphql/types.py index d2bf4b416..ac2549616 100644 --- a/netbox/dcim/graphql/types.py +++ b/netbox/dcim/graphql/types.py @@ -613,7 +613,6 @@ class PowerPortTemplateType(ModularComponentTemplateType): filters=RackTypeFilter ) class RackTypeType(NetBoxObjectType): - _name: str manufacturer: Annotated["ManufacturerType", strawberry.lazy('dcim.graphql.types')] diff --git a/netbox/dcim/migrations/0188_racktype.py b/netbox/dcim/migrations/0188_racktype.py index 18e4152b6..b23169093 100644 --- a/netbox/dcim/migrations/0188_racktype.py +++ b/netbox/dcim/migrations/0188_racktype.py @@ -37,14 +37,7 @@ class Migration(migrations.Migration): related_name='rack_types', to='dcim.manufacturer' )), - ('name', models.CharField(max_length=100)), - ('_name', utilities.fields.NaturalOrderingField( - 'name', - blank=True, - max_length=100, - naturalize_function=utilities.ordering.naturalize - ), - ), + ('model', models.CharField(max_length=100)), ('slug', models.SlugField(max_length=100, unique=True)), ('form_factor', models.CharField(blank=True, max_length=50)), ('width', models.PositiveSmallIntegerField(default=19)), @@ -71,7 +64,7 @@ class Migration(migrations.Migration): options={ 'verbose_name': 'racktype', 'verbose_name_plural': 'racktypes', - 'ordering': ('_name', 'pk'), + 'ordering': ('manufacturer', 'model'), }, ), migrations.RenameField( @@ -90,4 +83,16 @@ class Migration(migrations.Migration): to='dcim.racktype', ), ), + migrations.AddConstraint( + model_name='racktype', + constraint=models.UniqueConstraint( + fields=('manufacturer', 'model'), name='dcim_racktype_unique_manufacturer_model' + ), + ), + migrations.AddConstraint( + model_name='racktype', + constraint=models.UniqueConstraint( + fields=('manufacturer', 'slug'), name='dcim_racktype_unique_manufacturer_slug' + ), + ), ] diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index 8457271f4..68088b63a 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -136,15 +136,10 @@ class RackType(RackBase): on_delete=models.PROTECT, related_name='rack_types' ) - name = models.CharField( - verbose_name=_('name'), + model = models.CharField( + verbose_name=_('model'), max_length=100 ) - _name = NaturalOrderingField( - target_field='name', - max_length=100, - blank=True - ) slug = models.SlugField( verbose_name=_('slug'), max_length=100, @@ -160,19 +155,29 @@ class RackType(RackBase): ) class Meta: - ordering = ('_name', 'pk') # (site, location, name) may be non-unique + ordering = ('manufacturer', 'model') + constraints = ( + models.UniqueConstraint( + fields=('manufacturer', 'model'), + name='%(app_label)s_%(class)s_unique_manufacturer_model' + ), + models.UniqueConstraint( + fields=('manufacturer', 'slug'), + name='%(app_label)s_%(class)s_unique_manufacturer_slug' + ), + ) verbose_name = _('rack type') verbose_name_plural = _('rack types') def __str__(self): - return self.name + return self.model def get_absolute_url(self): return reverse('dcim:racktype', args=[self.pk]) @property def full_name(self): - return f"{self.manufacturer} {self.name}" + return f"{self.manufacturer} {self.model}" def clean(self): super().clean() diff --git a/netbox/dcim/search.py b/netbox/dcim/search.py index 32add68d0..38c1843fe 100644 --- a/netbox/dcim/search.py +++ b/netbox/dcim/search.py @@ -246,7 +246,7 @@ class PowerPortIndex(SearchIndex): class RackTypeIndex(SearchIndex): model = models.RackType fields = ( - ('name', 100), + ('model', 100), ('description', 500), ('comments', 5000), ) diff --git a/netbox/dcim/tables/racks.py b/netbox/dcim/tables/racks.py index b8295c286..a6b704161 100644 --- a/netbox/dcim/tables/racks.py +++ b/netbox/dcim/tables/racks.py @@ -50,9 +50,8 @@ class RackRoleTable(NetBoxTable): # class RackTypeTable(NetBoxTable): - name = tables.Column( - verbose_name=_('Name'), - order_by=('_name',), + model = tables.Column( + verbose_name=_('Model'), linkify=True ) manufacturer = tables.Column( @@ -96,12 +95,12 @@ class RackTypeTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = RackType fields = ( - 'pk', 'id', 'name', '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', 'instance_count', 'tags', 'created', 'last_updated', ) default_columns = ( - 'pk', 'name', 'manufacturer', 'type', 'u_height', 'description', 'instance_count', + 'pk', 'model', 'manufacturer', 'type', 'u_height', 'description', 'instance_count', ) diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index f41ad44ff..b690007be 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -273,7 +273,7 @@ class RackRoleTest(APIViewTestCases.APIViewTestCase): class RackTypeTest(APIViewTestCases.APIViewTestCase): model = RackType - brief_fields = ['description', 'display', 'id', 'manufacturer', 'name', 'slug', 'url'] + brief_fields = ['description', 'display', 'id', 'manufacturer', 'model', 'slug', 'url'] bulk_update_data = { 'description': 'new description', } @@ -287,26 +287,26 @@ class RackTypeTest(APIViewTestCases.APIViewTestCase): Manufacturer.objects.bulk_create(manufacturers) rack_types = ( - RackType(manufacturer=manufacturers[0], name='Rack Type 1', slug='rack-type-1'), - RackType(manufacturer=manufacturers[0], name='Rack Type 2', slug='rack-type-2'), - RackType(manufacturer=manufacturers[0], name='Rack Type 3', slug='rack-type-3'), + RackType(manufacturer=manufacturers[0], model='Rack Type 1', slug='rack-type-1'), + RackType(manufacturer=manufacturers[0], model='Rack Type 2', slug='rack-type-2'), + RackType(manufacturer=manufacturers[0], model='Rack Type 3', slug='rack-type-3'), ) RackType.objects.bulk_create(rack_types) cls.create_data = [ { 'manufacturer': manufacturers[1].pk, - 'name': 'Rack Type 4', + 'model': 'Rack Type 4', 'slug': 'rack-type-4', }, { 'manufacturer': manufacturers[1].pk, - 'name': 'Rack Type 5', + 'model': 'Rack Type 5', 'slug': 'rack-type-5', }, { 'manufacturer': manufacturers[1].pk, - 'name': 'Rack Type 6', + 'model': 'Rack Type 6', 'slug': 'rack-type-6', }, ] diff --git a/netbox/dcim/tests/test_filtersets.py b/netbox/dcim/tests/test_filtersets.py index e76813874..156815474 100644 --- a/netbox/dcim/tests/test_filtersets.py +++ b/netbox/dcim/tests/test_filtersets.py @@ -482,7 +482,7 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests): racks = ( RackType( manufacturer=manufacturers[0], - name='RackType 1', + model='RackType 1', slug='rack-type-1', form_factor=RackFormFactorChoices.TYPE_2POST, width=RackWidthChoices.WIDTH_19IN, @@ -500,7 +500,7 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests): ), RackType( manufacturer=manufacturers[1], - name='RackType 2', + model='RackType 2', slug='rack-type-2', form_factor=RackFormFactorChoices.TYPE_4POST, width=RackWidthChoices.WIDTH_21IN, @@ -518,7 +518,7 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests): ), RackType( manufacturer=manufacturers[2], - name='RackType 3', + model='RackType 3', slug='rack-type-3', form_factor=RackFormFactorChoices.TYPE_CABINET, width=RackWidthChoices.WIDTH_23IN, @@ -548,8 +548,8 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'manufacturer': [manufacturers[0].slug, manufacturers[1].slug]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) - def test_name(self): - params = {'name': ['RackType 1', 'RackType 2']} + def test_model(self): + params = {'model': ['RackType 1', 'RackType 2']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) def test_slug(self): @@ -661,7 +661,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests): rack_types = ( RackType( manufacturer=manufacturers[0], - name='RackType 1', + model='RackType 1', slug='rack-type-1', form_factor=RackFormFactorChoices.TYPE_2POST, width=RackWidthChoices.WIDTH_19IN, @@ -679,7 +679,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests): ), RackType( manufacturer=manufacturers[1], - name='RackType 2', + model='RackType 2', slug='rack-type-2', form_factor=RackFormFactorChoices.TYPE_4POST, width=RackWidthChoices.WIDTH_21IN, diff --git a/netbox/dcim/tests/test_models.py b/netbox/dcim/tests/test_models.py index 229edc0de..148b9e35f 100644 --- a/netbox/dcim/tests/test_models.py +++ b/netbox/dcim/tests/test_models.py @@ -82,7 +82,7 @@ class RackTypeTestCase(TestCase): RackType.objects.create( manufacturer=manufacturer, - name='RackType 1', + model='RackType 1', slug='rack-type-1', width=11, u_height=22, diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index e9002665b..c8763e5b9 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -346,9 +346,9 @@ class RackTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase): Manufacturer.objects.bulk_create(manufacturers) rack_types = ( - RackType(manufacturer=manufacturers[0], name='RackType 1', slug='rack-type-1',), - RackType(manufacturer=manufacturers[0], name='RackType 2', slug='rack-type-2',), - RackType(manufacturer=manufacturers[0], name='RackType 3', slug='rack-type-3',), + RackType(manufacturer=manufacturers[0], model='RackType 1', slug='rack-type-1',), + RackType(manufacturer=manufacturers[0], model='RackType 2', slug='rack-type-2',), + RackType(manufacturer=manufacturers[0], model='RackType 3', slug='rack-type-3',), ) RackType.objects.bulk_create(rack_types) @@ -356,7 +356,7 @@ class RackTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase): cls.form_data = { 'manufacturer': manufacturers[1].pk, - 'name': 'RackType X', + 'model': 'RackType X', 'slug': 'rack-type-x', 'type': RackFormFactorChoices.TYPE_CABINET, 'width': RackWidthChoices.WIDTH_19IN, @@ -374,14 +374,14 @@ class RackTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase): } cls.csv_data = ( - "manufacturer,name,slug,width,u_height,weight,max_weight,weight_unit", + "manufacturer,model,slug,width,u_height,weight,max_weight,weight_unit", "Manufacturer 1,RackType 4,rack-type-4,19,42,100,2000,kg", "Manufacturer 1,RackType 5,rack-type-5,19,42,100,2000,kg", "Manufacturer 1,RackType 6,rack-type-6,19,42,100,2000,kg", ) cls.csv_update_data = ( - "id,name", + "id,model", f"{rack_types[0].pk},RackType 7", f"{rack_types[1].pk},RackType 8", f"{rack_types[2].pk},RackType 9", diff --git a/netbox/templates/dcim/racktype.html b/netbox/templates/dcim/racktype.html index c4e445146..8a1971af9 100644 --- a/netbox/templates/dcim/racktype.html +++ b/netbox/templates/dcim/racktype.html @@ -17,8 +17,8 @@