From 4ffe1866c55522f49736d435d6a96cd9b7c29a20 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 2 Nov 2018 09:17:51 -0400 Subject: [PATCH] Closes #1444: Add field to Rack model --- CHANGELOG.md | 1 + netbox/dcim/api/serializers.py | 5 +++-- netbox/dcim/filters.py | 4 +++- netbox/dcim/forms.py | 10 +++++++--- ...{0068_rack_status.py => 0068_rack_new_fields.py} | 9 +++++++-- netbox/dcim/models.py | 13 +++++++++++-- netbox/templates/dcim/rack.html | 10 ++++++++++ netbox/templates/dcim/rack_edit.html | 1 + 8 files changed, 43 insertions(+), 10 deletions(-) rename netbox/dcim/migrations/{0068_rack_status.py => 0068_rack_new_fields.py} (60%) diff --git a/CHANGELOG.md b/CHANGELOG.md index c259eeeaa..91a4059ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ v2.5.0 (FUTURE) ## Enhancements +* [#1444](https://github.com/digitalocean/netbox/issues/1444) - Added an `asset_tag` field for racks * [#2000](https://github.com/digitalocean/netbox/issues/2000) - Dropped support for Python 2 * [#2104](https://github.com/digitalocean/netbox/issues/2104) - Added a `status` field for racks * [#2292](https://github.com/digitalocean/netbox/issues/2292) - Removed the deprecated UserAction model diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index b43883f40..d1cb8bd39 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -126,8 +126,9 @@ class RackSerializer(TaggitSerializer, CustomFieldModelSerializer): class Meta: model = Rack fields = [ - 'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'status', 'role', 'serial', 'type', - 'width', 'u_height', 'desc_units', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', + 'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'status', 'role', 'serial', + 'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'comments', 'tags', 'custom_fields', 'created', + 'last_updated', ] # Omit the UniqueTogetherValidator that would be automatically added to validate (group, facility_id). This # prevents facility_id from being interpreted as a required field. diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index b7d69a338..a6143065c 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -194,13 +194,14 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet): to_field_name='slug', label='Role (slug)', ) + asset_tag = NullableCharFieldFilter() tag = django_filters.CharFilter( name='tags__slug', ) class Meta: model = Rack - fields = ['name', 'serial', 'type', 'width', 'u_height', 'desc_units'] + fields = ['name', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'desc_units'] def search(self, queryset, name, value): if not value.strip(): @@ -209,6 +210,7 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet): Q(name__icontains=value) | Q(facility_id__icontains=value) | Q(serial__icontains=value.strip()) | + Q(asset_tag__icontains=value.strip()) | Q(comments__icontains=value) ) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 6e6abfd15..770f3ab8a 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -306,8 +306,8 @@ class RackForm(BootstrapMixin, TenancyForm, CustomFieldForm): class Meta: model = Rack fields = [ - 'site', 'group', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial', 'type', - 'width', 'u_height', 'desc_units', 'comments', 'tags', + 'site', 'group', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial', 'asset_tag', + 'type', 'width', 'u_height', 'desc_units', 'comments', 'tags', ] help_texts = { 'site': "The site at which the rack exists", @@ -437,6 +437,10 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor required=False, label='Serial Number' ) + asset_tag = forms.CharField( + max_length=50, + required=False + ) type = forms.ChoiceField( choices=add_blank_choice(RACK_TYPE_CHOICES), required=False @@ -459,7 +463,7 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor ) class Meta: - nullable_fields = ['group', 'tenant', 'role', 'serial', 'comments'] + nullable_fields = ['group', 'tenant', 'role', 'serial', 'asset_tag', 'comments'] class RackFilterForm(BootstrapMixin, CustomFieldFilterForm): diff --git a/netbox/dcim/migrations/0068_rack_status.py b/netbox/dcim/migrations/0068_rack_new_fields.py similarity index 60% rename from netbox/dcim/migrations/0068_rack_status.py rename to netbox/dcim/migrations/0068_rack_new_fields.py index e190ff7df..b0a3e1958 100644 --- a/netbox/dcim/migrations/0068_rack_status.py +++ b/netbox/dcim/migrations/0068_rack_new_fields.py @@ -1,7 +1,7 @@ -# Generated by Django 2.0.9 on 2018-11-01 19:44 - from django.db import migrations, models +import utilities.fields + class Migration(migrations.Migration): @@ -15,4 +15,9 @@ class Migration(migrations.Migration): name='status', field=models.PositiveSmallIntegerField(default=3), ), + migrations.AddField( + model_name='rack', + name='asset_tag', + field=utilities.fields.NullableCharField(blank=True, max_length=50, null=True, unique=True), + ), ] diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 00e522082..da8ee29bc 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -480,6 +480,14 @@ class Rack(ChangeLoggedModel, CustomFieldModel): blank=True, verbose_name='Serial number' ) + asset_tag = NullableCharField( + max_length=50, + blank=True, + null=True, + unique=True, + verbose_name='Asset tag', + help_text='A unique tag used to identify this rack' + ) type = models.PositiveSmallIntegerField( choices=RACK_TYPE_CHOICES, blank=True, @@ -518,8 +526,8 @@ class Rack(ChangeLoggedModel, CustomFieldModel): tags = TaggableManager() csv_headers = [ - 'site', 'group_name', 'name', 'facility_id', 'tenant', 'status', 'role', 'type', 'serial', 'width', 'u_height', - 'desc_units', 'comments', + 'site', 'group_name', 'name', 'facility_id', 'tenant', 'status', 'role', 'type', 'serial', 'asset_tag', 'width', + 'u_height', 'desc_units', 'comments', ] class Meta: @@ -579,6 +587,7 @@ class Rack(ChangeLoggedModel, CustomFieldModel): self.role.name if self.role else None, self.get_type_display() if self.type else None, self.serial, + self.asset_tag, self.width, self.u_height, self.desc_units, diff --git a/netbox/templates/dcim/rack.html b/netbox/templates/dcim/rack.html index 52f841eb3..9427eb600 100644 --- a/netbox/templates/dcim/rack.html +++ b/netbox/templates/dcim/rack.html @@ -131,6 +131,16 @@ {% endif %} + + Asset Tag + + {% if rack.asset_tag %} + {{ rack.asset_tag }} + {% else %} + N/A + {% endif %} + + Devices diff --git a/netbox/templates/dcim/rack_edit.html b/netbox/templates/dcim/rack_edit.html index 0326e9523..798de0313 100644 --- a/netbox/templates/dcim/rack_edit.html +++ b/netbox/templates/dcim/rack_edit.html @@ -12,6 +12,7 @@ {% render_field form.status %} {% render_field form.role %} {% render_field form.serial %} + {% render_field form.asset_tag %}