Skip to content

Commit

Permalink
netbox-community#180: Added type and width fields to Rack model
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremystretch committed Aug 8, 2016
1 parent 377347d commit bb3da16
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 12 deletions.
2 changes: 1 addition & 1 deletion netbox/dcim/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class RackGroupAdmin(admin.ModelAdmin):

@admin.register(Rack)
class RackAdmin(admin.ModelAdmin):
list_display = ['name', 'facility_id', 'site', 'u_height']
list_display = ['name', 'facility_id', 'site', 'type', 'width', 'u_height']


#
Expand Down
7 changes: 4 additions & 3 deletions netbox/dcim/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ class RackSerializer(serializers.ModelSerializer):

class Meta:
model = Rack
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'u_height', 'comments']
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'type', 'width', 'u_height',
'comments']


class RackNestedSerializer(RackSerializer):
Expand All @@ -72,8 +73,8 @@ class RackDetailSerializer(RackSerializer):
rear_units = serializers.SerializerMethodField()

class Meta(RackSerializer.Meta):
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'u_height', 'comments',
'front_units', 'rear_units']
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'type', 'width', 'u_height',
'comments', 'front_units', 'rear_units']

def get_front_units(self, obj):
units = obj.get_rack_units(face=RACK_FACE_FRONT)
Expand Down
25 changes: 21 additions & 4 deletions netbox/dcim/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@
from tenancy.forms import bulkedit_tenant_choices
from tenancy.models import Tenant
from utilities.forms import (
APISelect, BootstrapMixin, BulkImportForm, CommentField, CSVDataField, ExpandableNameField,
APISelect, add_blank_choice, BootstrapMixin, BulkImportForm, CommentField, CSVDataField, ExpandableNameField,
FlexibleModelChoiceField, Livesearch, SelectWithDisabled, SmallTextarea, SlugField,
)

from .models import (
DeviceBay, DeviceBayTemplate, CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_PLANNED, CONNECTION_STATUS_CONNECTED,
ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceRole, DeviceType,
Interface, IFACE_FF_VIRTUAL, InterfaceConnection, InterfaceTemplate, Manufacturer, Module, Platform, PowerOutlet,
PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHILD
PowerOutletTemplate, PowerPort, PowerPortTemplate, RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, Rack, RackGroup, Site,
STATUS_CHOICES, SUBDEVICE_ROLE_CHILD
)


Expand Down Expand Up @@ -135,7 +136,7 @@ class RackForm(forms.ModelForm, BootstrapMixin):

class Meta:
model = Rack
fields = ['site', 'group', 'name', 'facility_id', 'tenant', 'u_height', 'comments']
fields = ['site', 'group', 'name', 'facility_id', 'tenant', 'type', 'width', 'u_height', 'comments']
help_texts = {
'site': "The site at which the rack exists",
'name': "Organizational rack name",
Expand Down Expand Up @@ -165,10 +166,11 @@ class RackFromCSVForm(forms.ModelForm):
group_name = forms.CharField(required=False)
tenant = forms.ModelChoiceField(Tenant.objects.all(), to_field_name='name', required=False,
error_messages={'invalid_choice': 'Tenant not found.'})
type = forms.CharField(required=False)

class Meta:
model = Rack
fields = ['site', 'group_name', 'name', 'facility_id', 'tenant', 'u_height']
fields = ['site', 'group_name', 'name', 'facility_id', 'tenant', 'type', 'width', 'u_height']

def clean(self):

Expand All @@ -182,6 +184,19 @@ def clean(self):
except RackGroup.DoesNotExist:
self.add_error('group_name', "Invalid rack group ({})".format(group))

def clean_type(self):
rack_type = self.cleaned_data['type']
if not rack_type:
return None
try:
choices = {v.lower(): k for k, v in RACK_TYPE_CHOICES}
return choices[rack_type.lower()]
except KeyError:
raise forms.ValidationError('Invalid rack type ({}). Valid choices are: {}.'.format(
rack_type,
', '.join({v: k for k, v in RACK_TYPE_CHOICES}),
))


class RackImportForm(BulkImportForm, BootstrapMixin):
csv = CSVDataField(csv_form=RackFromCSVForm)
Expand All @@ -192,6 +207,8 @@ class RackBulkEditForm(forms.Form, BootstrapMixin):
site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False)
group = forms.ModelChoiceField(queryset=RackGroup.objects.all(), required=False)
tenant = forms.TypedChoiceField(choices=bulkedit_tenant_choices, coerce=int, required=False, label='Tenant')
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)')
comments = CommentField()

Expand Down
25 changes: 25 additions & 0 deletions netbox/dcim/migrations/0014_rack_add_type_width.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.8 on 2016-08-08 21:11
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('dcim', '0013_add_interface_form_factors'),
]

operations = [
migrations.AddField(
model_name='rack',
name='type',
field=models.PositiveSmallIntegerField(blank=True, choices=[(100, b'2-post frame'), (200, b'4-post frame'), (300, b'4-post cabinet'), (1000, b'Wall-mounted frame'), (1100, b'Wall-mounted cabinet')], null=True, verbose_name=b'Type'),
),
migrations.AddField(
model_name='rack',
name='width',
field=models.PositiveSmallIntegerField(choices=[(19, b'19 inches'), (23, b'23 inches')], default=19, help_text=b'Rail-to-rail width', verbose_name=b'Width'),
),
]
23 changes: 23 additions & 0 deletions netbox/dcim/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,26 @@
from .fields import ASNField, MACAddressField


RACK_TYPE_2POST = 100
RACK_TYPE_4POST = 200
RACK_TYPE_CABINET = 300
RACK_TYPE_WALLFRAME = 1000
RACK_TYPE_WALLCABINET = 1100
RACK_TYPE_CHOICES = (
(RACK_TYPE_2POST, '2-post frame'),
(RACK_TYPE_4POST, '4-post frame'),
(RACK_TYPE_CABINET, '4-post cabinet'),
(RACK_TYPE_WALLFRAME, 'Wall-mounted frame'),
(RACK_TYPE_WALLCABINET, 'Wall-mounted cabinet'),
)

RACK_WIDTH_19IN = 19
RACK_WIDTH_23IN = 23
RACK_WIDTH_CHOICES = (
(RACK_WIDTH_19IN, '19 inches'),
(RACK_WIDTH_23IN, '23 inches'),
)

RACK_FACE_FRONT = 0
RACK_FACE_REAR = 1
RACK_FACE_CHOICES = [
Expand Down Expand Up @@ -284,6 +304,9 @@ class Rack(CreatedUpdatedModel):
site = models.ForeignKey('Site', related_name='racks', on_delete=models.PROTECT)
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)
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')
u_height = models.PositiveSmallIntegerField(default=42, verbose_name='Height (U)')
comments = models.TextField(blank=True)

Expand Down
6 changes: 6 additions & 0 deletions netbox/dcim/tests/test_apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class SiteTest(APITestCase):
'site',
'group',
'tenant',
'type',
'width',
'u_height',
'comments'
]
Expand Down Expand Up @@ -118,6 +120,8 @@ class RackTest(APITestCase):
'site',
'group',
'tenant',
'type',
'width',
'u_height',
'comments'
]
Expand All @@ -130,6 +134,8 @@ class RackTest(APITestCase):
'site',
'group',
'tenant',
'type',
'width',
'u_height',
'comments',
'front_units',
Expand Down
2 changes: 1 addition & 1 deletion netbox/dcim/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def update_objects(self, pk_list, form):
fields_to_update['tenant'] = None
elif form.cleaned_data['tenant']:
fields_to_update['tenant'] = form.cleaned_data['tenant']
for field in ['site', 'group', 'tenant', 'u_height', 'comments']:
for field in ['site', 'group', 'tenant', 'type', 'width', 'u_height', 'comments']:
if form.cleaned_data[field]:
fields_to_update[field] = form.cleaned_data[field]

Expand Down
14 changes: 14 additions & 0 deletions netbox/templates/dcim/rack.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ <h1>Rack {{ rack.name }}</h1>
{% endif %}
</td>
</tr>
<tr>
<td>Type</td>
<td>
{% if rack.type %}
{{ rack.get_type_display }}
{% else %}
<span class="text-muted">None</span>
{% endif %}
</td>
</tr>
<tr>
<td>Width</td>
<td>{{ rack.get_width_display }}</td>
</tr>
<tr>
<td>Height</td>
<td>{{ rack.u_height }}U</td>
Expand Down
15 changes: 13 additions & 2 deletions netbox/templates/dcim/rack_bulk_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,24 @@
{% block title %}Rack Bulk Edit{% endblock %}

{% block select_objects_table %}
<tr>
<th>Name</th>
<th>Site</th>
<th>Group</th>
<th>Tenant</th>
<th>Type</th>
<th>Width</th>
<th>Height</th>
</tr>
{% for rack in selected_objects %}
<tr>
<td><a href="{% url 'dcim:rack' pk=rack.pk %}">{{ rack }}</a></td>
<td>{{ rack.facility_id }}</td>
<td>{{ rack.site }}</td>
<td>{{ rack.group }}</td>
<td>{{ rack.tenant }}</td>
<td>{{ rack.u_height }}</td>
<td>{{ rack.get_type_display }}</td>
<td>{{ rack.get_width_display }}</td>
<td>{{ rack.u_height }}U</td>
</tr>
{% endfor %}
{% endblock %}
2 changes: 2 additions & 0 deletions netbox/templates/dcim/rack_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
{% render_field form.name %}
{% render_field form.facility_id %}
{% render_field form.tenant %}
{% render_field form.type %}
{% render_field form.width %}
{% render_field form.u_height %}
</div>
</div>
Expand Down
12 changes: 11 additions & 1 deletion netbox/templates/dcim/rack_import.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ <h4>CSV Format</h4>
<td>Name of tenant (optional)</td>
<td>Pied Piper</td>
</tr>
<tr>
<td>Type</td>
<td>Rack type (optional)</td>
<td>4-post cabinet</td>
</tr>
<tr>
<td>Width</td>
<td>Rail-to-rail width (19 or 23 inches)</td>
<td>19</td>
</tr>
<tr>
<td>Height</td>
<td>Height in rack units</td>
Expand All @@ -61,7 +71,7 @@ <h4>CSV Format</h4>
</tbody>
</table>
<h4>Example</h4>
<pre>DC-4,Cage 1400,R101,J12.100,Pied Piper,42</pre>
<pre>DC-4,Cage 1400,R101,J12.100,Pied Piper,4-post cabinet,19,42</pre>
</div>
</div>
{% endblock %}
7 changes: 7 additions & 0 deletions netbox/utilities/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ def expand_pattern(string):
yield "{}{}{}".format(lead, i, remnant)


def add_blank_choice(choices):
"""
Add a blank choice to the beginning of a choices list.
"""
return ((None, '---------'),) + choices


#
# Widgets
#
Expand Down

0 comments on commit bb3da16

Please sign in to comment.