Skip to content

Commit

Permalink
Closes #1758: Added 'status' field to Site model
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremystretch committed Jan 25, 2018
1 parent 4df128d commit ed10a99
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 19 deletions.
7 changes: 4 additions & 3 deletions netbox/dcim/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from circuits.models import Circuit, CircuitTermination
from dcim.constants import (
CONNECTION_STATUS_CHOICES, DEVICE_STATUS_CHOICES, IFACE_FF_CHOICES, IFACE_MODE_CHOICES, IFACE_ORDERING_CHOICES,
RACK_FACE_CHOICES, RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, SUBDEVICE_ROLE_CHOICES,
RACK_FACE_CHOICES, RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, SITE_STATUS_CHOICES, SUBDEVICE_ROLE_CHOICES,
)
from dcim.models import (
ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
Expand Down Expand Up @@ -56,14 +56,15 @@ class Meta:
#

class SiteSerializer(CustomFieldModelSerializer):
status = ChoiceFieldSerializer(choices=SITE_STATUS_CHOICES)
region = NestedRegionSerializer()
tenant = NestedTenantSerializer()
time_zone = TimeZoneField(required=False)

class Meta:
model = Site
fields = [
'id', 'name', 'slug', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'physical_address',
'id', 'name', 'slug', 'status', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'physical_address',
'shipping_address', 'contact_name', 'contact_phone', 'contact_email', 'comments', 'custom_fields',
'created', 'last_updated', 'count_prefixes', 'count_vlans', 'count_racks', 'count_devices',
'count_circuits',
Expand All @@ -84,7 +85,7 @@ class WritableSiteSerializer(CustomFieldModelSerializer):
class Meta:
model = Site
fields = [
'id', 'name', 'slug', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'physical_address',
'id', 'name', 'slug', 'status', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'physical_address',
'shipping_address', 'contact_name', 'contact_phone', 'contact_email', 'comments', 'custom_fields',
'created', 'last_updated',
]
Expand Down
14 changes: 12 additions & 2 deletions netbox/dcim/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,18 @@
[DEVICE_STATUS_INVENTORY, 'Inventory'],
]

# Bootstrap CSS classes for device stasuses
DEVICE_STATUS_CLASSES = {
# Site statuses
SITE_STATUS_ACTIVE = 1
SITE_STATUS_PLANNED = 2
SITE_STATUS_RETIRED = 4
SITE_STATUS_CHOICES = [
[SITE_STATUS_ACTIVE, 'Active'],
[SITE_STATUS_PLANNED, 'Planned'],
[SITE_STATUS_RETIRED, 'Retired'],
]

# Bootstrap CSS classes for device statuses
STATUS_CLASSES = {
0: 'warning',
1: 'success',
2: 'info',
Expand Down
2 changes: 1 addition & 1 deletion netbox/dcim/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):

class Meta:
model = Site
fields = ['q', 'name', 'slug', 'facility', 'asn', 'contact_name', 'contact_phone', 'contact_email']
fields = ['q', 'name', 'slug', 'status', 'facility', 'asn', 'contact_name', 'contact_phone', 'contact_email']

def search(self, queryset, name, value):
if not value.strip():
Expand Down
22 changes: 18 additions & 4 deletions netbox/dcim/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from .constants import (
CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_CONNECTED, DEVICE_STATUS_CHOICES, IFACE_FF_CHOICES, IFACE_FF_LAG,
IFACE_MODE_ACCESS, IFACE_MODE_CHOICES, IFACE_MODE_TAGGED_ALL, IFACE_ORDERING_CHOICES, RACK_FACE_CHOICES,
RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, RACK_WIDTH_19IN, RACK_WIDTH_23IN, SUBDEVICE_ROLE_CHILD,
RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, RACK_WIDTH_19IN, RACK_WIDTH_23IN, SITE_STATUS_CHOICES, SUBDEVICE_ROLE_CHILD,
SUBDEVICE_ROLE_PARENT, SUBDEVICE_ROLE_CHOICES,
)
from .formfields import MACAddressFormField
Expand Down Expand Up @@ -104,7 +104,7 @@ class SiteForm(BootstrapMixin, TenancyForm, CustomFieldForm):
class Meta:
model = Site
fields = [
'name', 'slug', 'region', 'tenant_group', 'tenant', 'facility', 'asn', 'physical_address',
'name', 'slug', 'status', 'region', 'tenant_group', 'tenant', 'facility', 'asn', 'physical_address',
'shipping_address', 'contact_name', 'contact_phone', 'contact_email', 'time_zone', 'comments',
]
widgets = {
Expand All @@ -121,6 +121,11 @@ class Meta:


class SiteCSVForm(forms.ModelForm):
status = CSVChoiceField(
choices=DEVICE_STATUS_CHOICES,
required=False,
help_text='Operational status'
)
region = forms.ModelChoiceField(
queryset=Region.objects.all(),
required=False,
Expand All @@ -143,7 +148,7 @@ class SiteCSVForm(forms.ModelForm):
class Meta:
model = Site
fields = [
'name', 'slug', 'region', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address',
'name', 'slug', 'status', 'region', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address',
'contact_name', 'contact_phone', 'contact_email', 'time_zone', 'comments',
]
help_texts = {
Expand All @@ -155,6 +160,7 @@ class Meta:

class SiteBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
pk = forms.ModelMultipleChoiceField(queryset=Site.objects.all(), widget=forms.MultipleHiddenInput)
status = forms.ChoiceField(choices=add_blank_choice(SITE_STATUS_CHOICES), required=False, initial='')
region = TreeNodeChoiceField(queryset=Region.objects.all(), required=False)
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
asn = forms.IntegerField(min_value=1, max_value=4294967295, required=False, label='ASN')
Expand All @@ -164,9 +170,17 @@ class Meta:
nullable_fields = ['region', 'tenant', 'asn', 'time_zone']


def site_status_choices():
status_counts = {}
for status in Site.objects.values('status').annotate(count=Count('status')).order_by('status'):
status_counts[status['status']] = status['count']
return [(s[0], '{} ({})'.format(s[1], status_counts.get(s[0], 0))) for s in SITE_STATUS_CHOICES]


class SiteFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Site
q = forms.CharField(required=False, label='Search')
status = forms.MultipleChoiceField(choices=site_status_choices, required=False)
region = FilterTreeNodeMultipleChoiceField(
queryset=Region.objects.annotate(filter_count=Count('sites')),
to_field_name='slug',
Expand Down Expand Up @@ -889,7 +903,7 @@ class BaseDeviceCSVForm(forms.ModelForm):
)
status = CSVChoiceField(
choices=DEVICE_STATUS_CHOICES,
help_text='Operational status of device'
help_text='Operational status'
)

class Meta:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-19 21:53
# Generated by Django 1.11.6 on 2018-01-25 17:57
from __future__ import unicode_literals

from django.db import migrations
from django.db import migrations, models
import timezone_field.fields


Expand All @@ -13,6 +13,11 @@ class Migration(migrations.Migration):
]

operations = [
migrations.AddField(
model_name='site',
name='status',
field=models.PositiveSmallIntegerField(choices=[[1, 'Active'], [2, 'Planned'], [4, 'Retired']], default=1),
),
migrations.AddField(
model_name='site',
name='time_zone',
Expand Down
9 changes: 7 additions & 2 deletions netbox/dcim/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class Site(CreatedUpdatedModel, CustomFieldModel):
"""
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(unique=True)
status = models.PositiveSmallIntegerField(choices=SITE_STATUS_CHOICES, default=SITE_STATUS_ACTIVE)
region = models.ForeignKey('Region', related_name='sites', blank=True, null=True, on_delete=models.SET_NULL)
tenant = models.ForeignKey(Tenant, related_name='sites', blank=True, null=True, on_delete=models.PROTECT)
facility = models.CharField(max_length=50, blank=True)
Expand All @@ -100,7 +101,7 @@ class Site(CreatedUpdatedModel, CustomFieldModel):
objects = SiteManager()

csv_headers = [
'name', 'slug', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'contact_name', 'contact_phone',
'name', 'slug', 'status', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'contact_name', 'contact_phone',
'contact_email',
]

Expand All @@ -117,6 +118,7 @@ def to_csv(self):
return csv_format([
self.name,
self.slug,
self.get_status_display(),
self.region.name if self.region else None,
self.tenant.name if self.tenant else None,
self.facility,
Expand All @@ -127,6 +129,9 @@ def to_csv(self):
self.contact_email,
])

def get_status_class(self):
return STATUS_CLASSES[self.status]

@property
def count_prefixes(self):
return self.prefixes.count()
Expand Down Expand Up @@ -1088,7 +1093,7 @@ def get_children(self):
return Device.objects.filter(parent_bay__device=self.pk)

def get_status_class(self):
return DEVICE_STATUS_CLASSES[self.status]
return STATUS_CLASSES[self.status]

def get_rpc_client(self):
"""
Expand Down
11 changes: 6 additions & 5 deletions netbox/dcim/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
<label class="label" style="background-color: #{{ record.device_role.color }}">{{ value }}</label>
"""

DEVICE_STATUS = """
STATUS_LABEL = """
<span class="label label-{{ record.get_status_class }}">{{ record.get_status_display }}</span>
"""

Expand Down Expand Up @@ -145,12 +145,13 @@ class Meta(BaseTable.Meta):
class SiteTable(BaseTable):
pk = ToggleColumn()
name = tables.LinkColumn()
status = tables.TemplateColumn(template_code=STATUS_LABEL, verbose_name='Status')
region = tables.TemplateColumn(template_code=SITE_REGION_LINK)
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])

class Meta(BaseTable.Meta):
model = Site
fields = ('pk', 'name', 'facility', 'region', 'tenant', 'asn')
fields = ('pk', 'name', 'status', 'facility', 'region', 'tenant', 'asn')


class SiteDetailTable(SiteTable):
Expand All @@ -163,7 +164,7 @@ class SiteDetailTable(SiteTable):

class Meta(SiteTable.Meta):
fields = (
'pk', 'name', 'facility', 'region', 'tenant', 'asn', 'rack_count', 'device_count', 'prefix_count',
'pk', 'name', 'status', 'facility', 'region', 'tenant', 'asn', 'rack_count', 'device_count', 'prefix_count',
'vlan_count', 'circuit_count', 'vm_count',
)

Expand Down Expand Up @@ -409,7 +410,7 @@ class Meta(BaseTable.Meta):
class DeviceTable(BaseTable):
pk = ToggleColumn()
name = tables.TemplateColumn(template_code=DEVICE_LINK)
status = tables.TemplateColumn(template_code=DEVICE_STATUS, verbose_name='Status')
status = tables.TemplateColumn(template_code=STATUS_LABEL, verbose_name='Status')
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')])
Expand All @@ -436,7 +437,7 @@ class Meta(DeviceTable.Meta):

class DeviceImportTable(BaseTable):
name = tables.TemplateColumn(template_code=DEVICE_LINK, verbose_name='Name')
status = tables.TemplateColumn(template_code=DEVICE_STATUS, verbose_name='Status')
status = tables.TemplateColumn(template_code=STATUS_LABEL, verbose_name='Status')
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant')
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site')
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')], verbose_name='Rack')
Expand Down
6 changes: 6 additions & 0 deletions netbox/templates/dcim/site.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ <h1>{% block title %}{{ site }}{% endblock %}</h1>
<strong>Site</strong>
</div>
<table class="table table-hover panel-body attr-table">
<tr>
<td>Status</td>
<td>
<span class="label label-{{ site.get_status_class }}">{{ site.get_status_display }}</span>
</td>
</tr>
<tr>
<td>Region</td>
<td>
Expand Down
1 change: 1 addition & 0 deletions netbox/templates/dcim/site_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<div class="panel-body">
{% render_field form.name %}
{% render_field form.slug %}
{% render_field form.status %}
{% render_field form.region %}
{% render_field form.facility %}
{% render_field form.asn %}
Expand Down

0 comments on commit ed10a99

Please sign in to comment.