Browse Source

#1444: Added a serial number field to the rack model

Jeremy Stretch 7 years ago
parent
commit
35c2c8e8de

+ 4 - 4
netbox/dcim/api/serializers.py

@@ -142,8 +142,8 @@ class RackSerializer(CustomFieldModelSerializer):
     class Meta:
         model = Rack
         fields = [
-            'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'role', 'type', 'width', 'u_height',
-            'desc_units', 'comments', 'custom_fields',
+            'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'role', 'serial', 'type', 'width',
+            'u_height', 'desc_units', 'comments', 'custom_fields',
         ]
 
 
@@ -160,8 +160,8 @@ class WritableRackSerializer(CustomFieldModelSerializer):
     class Meta:
         model = Rack
         fields = [
-            'id', 'name', 'facility_id', 'site', 'group', 'tenant', 'role', 'type', 'width', 'u_height', 'desc_units',
-            'comments', 'custom_fields',
+            'id', 'name', 'facility_id', 'site', 'group', 'tenant', 'role', 'serial', 'type', 'width', 'u_height',
+            'desc_units', 'comments', 'custom_fields',
         ]
         # Omit the UniqueTogetherValidator that would be automatically added to validate (site, facility_id). This
         # prevents facility_id from being interpreted as a required field.

+ 2 - 1
netbox/dcim/filters.py

@@ -159,7 +159,7 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet):
 
     class Meta:
         model = Rack
-        fields = ['type', 'width', 'u_height', 'desc_units']
+        fields = ['serial', 'type', 'width', 'u_height', 'desc_units']
 
     def search(self, queryset, name, value):
         if not value.strip():
@@ -167,6 +167,7 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet):
         return queryset.filter(
             Q(name__icontains=value) |
             Q(facility_id__icontains=value) |
+            Q(serial__icontains=value.strip()) |
             Q(comments__icontains=value)
         )
 

+ 7 - 5
netbox/dcim/forms.py

@@ -232,8 +232,8 @@ class RackForm(BootstrapMixin, TenancyForm, CustomFieldForm):
     class Meta:
         model = Rack
         fields = [
-            'site', 'group', 'name', 'facility_id', 'tenant_group', 'tenant', 'role', 'type', 'width', 'u_height',
-            'desc_units', 'comments',
+            'site', 'group', 'name', 'facility_id', 'tenant_group', 'tenant', 'role', 'serial', 'type', 'width',
+            'u_height', 'desc_units', 'comments',
         ]
         help_texts = {
             'site': "The site at which the rack exists",
@@ -293,7 +293,8 @@ class RackCSVForm(forms.ModelForm):
     class Meta:
         model = Rack
         fields = [
-            'site', 'group_name', 'name', 'facility_id', 'tenant', 'role', 'type', 'width', 'u_height', 'desc_units',
+            'site', 'group_name', 'name', 'facility_id', 'tenant', 'role', 'serial', 'type', 'width', 'u_height',
+            'desc_units',
         ]
         help_texts = {
             'name': 'Rack name',
@@ -321,6 +322,7 @@ class RackBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
     group = forms.ModelChoiceField(queryset=RackGroup.objects.all(), required=False, label='Group')
     tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
     role = forms.ModelChoiceField(queryset=RackRole.objects.all(), required=False)
+    serial = forms.CharField(max_length=50, required=False, label='Serial Number')
     type = forms.ChoiceField(choices=add_blank_choice(RACK_TYPE_CHOICES), required=False, label='Type')
     width = forms.ChoiceField(choices=add_blank_choice(RACK_WIDTH_CHOICES), required=False, label='Width')
     u_height = forms.IntegerField(required=False, label='Height (U)')
@@ -328,7 +330,7 @@ class RackBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
     comments = CommentField(widget=SmallTextarea)
 
     class Meta:
-        nullable_fields = ['group', 'tenant', 'role', 'comments']
+        nullable_fields = ['group', 'tenant', 'role', 'serial', 'comments']
 
 
 class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
@@ -938,7 +940,7 @@ class DeviceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
     serial = forms.CharField(max_length=50, required=False, label='Serial Number')
 
     class Meta:
-        nullable_fields = ['tenant', 'platform']
+        nullable_fields = ['tenant', 'platform', 'serial']
 
 
 def device_status_choices():

+ 20 - 0
netbox/dcim/migrations/0048_rack_serial.py

@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2017-10-09 18:50
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dcim', '0047_more_100ge_form_factors'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='rack',
+            name='serial',
+            field=models.CharField(blank=True, max_length=50, verbose_name='Serial number'),
+        ),
+    ]

+ 3 - 1
netbox/dcim/models.py

@@ -222,6 +222,7 @@ class Rack(CreatedUpdatedModel, CustomFieldModel):
     group = models.ForeignKey('RackGroup', related_name='racks', blank=True, null=True, on_delete=models.SET_NULL)
     tenant = models.ForeignKey(Tenant, blank=True, null=True, related_name='racks', on_delete=models.PROTECT)
     role = models.ForeignKey('RackRole', related_name='racks', blank=True, null=True, on_delete=models.PROTECT)
+    serial = models.CharField(max_length=50, blank=True, verbose_name='Serial number')
     type = models.PositiveSmallIntegerField(choices=RACK_TYPE_CHOICES, blank=True, null=True, verbose_name='Type')
     width = models.PositiveSmallIntegerField(choices=RACK_WIDTH_CHOICES, default=RACK_WIDTH_19IN, verbose_name='Width',
                                              help_text='Rail-to-rail width')
@@ -236,7 +237,8 @@ class Rack(CreatedUpdatedModel, CustomFieldModel):
     objects = RackManager()
 
     csv_headers = [
-        'site', 'group_name', 'name', 'facility_id', 'tenant', 'role', 'type', 'width', 'u_height', 'desc_units',
+        'site', 'group_name', 'name', 'facility_id', 'tenant', 'role', 'type', 'serial', 'width', 'u_height',
+        'desc_units',
     ]
 
     class Meta:

+ 23 - 6
netbox/templates/dcim/rack.html

@@ -113,6 +113,29 @@
                     </td>
                 </tr>
                 <tr>
+                    <td>Serial Number</td>
+                    <td>
+                        {% if rack.serial %}
+                            <span>{{ rack.serial }}</span>
+                        {% else %}
+                            <span class="text-muted">N/A</span>
+                        {% endif %}
+                    </td>
+                </tr>
+                <tr>
+                    <td>Devices</td>
+                    <td>
+                        <a href="{% url 'dcim:device_list' %}?rack_id={{ rack.id }}">{{ rack.devices.count }}</a>
+                    </td>
+                </tr>
+            </table>
+        </div>
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                <strong>Dimensions</strong>
+            </div>
+            <table class="table table-hover panel-body attr-table">
+                <tr>
                     <td>Type</td>
                     <td>
                         {% if rack.type %}
@@ -130,12 +153,6 @@
                     <td>Height</td>
                     <td>{{ rack.u_height }}U ({% if rack.desc_units %}descending{% else %}ascending{% endif %})</td>
                 </tr>
-                <tr>
-                    <td>Devices</td>
-                    <td>
-                        <a href="{% url 'dcim:device_list' %}?rack_id={{ rack.id }}">{{ rack.devices.count }}</a>
-                    </td>
-                </tr>
             </table>
         </div>
         {% with rack.get_custom_fields as custom_fields %}

+ 1 - 0
netbox/templates/dcim/rack_edit.html

@@ -10,6 +10,7 @@
             {% render_field form.facility_id %}
             {% render_field form.group %}
             {% render_field form.role %}
+            {% render_field form.serial %}
         </div>
     </div>
     <div class="panel panel-default">