Circuit.status (#3569)

This commit is contained in:
Jeremy Stretch 2019-11-07 11:10:46 -05:00
parent a2a6b754be
commit e09ad6915f
9 changed files with 97 additions and 33 deletions

View File

@ -1,7 +1,7 @@
from rest_framework import serializers from rest_framework import serializers
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
from circuits.constants import CIRCUIT_STATUS_CHOICES from circuits.choices import CircuitStatusChoices
from circuits.models import Provider, Circuit, CircuitTermination, CircuitType from circuits.models import Provider, Circuit, CircuitTermination, CircuitType
from dcim.api.nested_serializers import NestedCableSerializer, NestedSiteSerializer from dcim.api.nested_serializers import NestedCableSerializer, NestedSiteSerializer
from dcim.api.serializers import ConnectedEndpointSerializer from dcim.api.serializers import ConnectedEndpointSerializer
@ -41,7 +41,7 @@ class CircuitTypeSerializer(ValidatedModelSerializer):
class CircuitSerializer(TaggitSerializer, CustomFieldModelSerializer): class CircuitSerializer(TaggitSerializer, CustomFieldModelSerializer):
provider = NestedProviderSerializer() provider = NestedProviderSerializer()
status = ChoiceField(choices=CIRCUIT_STATUS_CHOICES, required=False) status = ChoiceField(choices=CircuitStatusChoices, required=False)
type = NestedCircuitTypeSerializer() type = NestedCircuitTypeSerializer()
tenant = NestedTenantSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True)
tags = TagListSerializerField(required=False) tags = TagListSerializerField(required=False)

View File

@ -0,0 +1,29 @@
from utilities.choices import ChoiceSet
class CircuitStatusChoices(ChoiceSet):
STATUS_DEPROVISIONING = 'deprovisioning'
STATUS_ACTIVE = 'active'
STATUS_PLANNED = 'planned'
STATUS_PROVISIONING = 'provisioning'
STATUS_OFFLINE = 'offline'
STATUS_DECOMMISSIONED = 'decommissioned'
CHOICES = (
(STATUS_PLANNED, 'Planned'),
(STATUS_PROVISIONING, 'Provisioning'),
(STATUS_ACTIVE, 'Active'),
(STATUS_OFFLINE, 'Offline'),
(STATUS_DEPROVISIONING, 'Deprovisioning'),
(STATUS_DECOMMISSIONED, 'Decommissioned'),
)
LEGACY_MAP = {
STATUS_DEPROVISIONING: 0,
STATUS_ACTIVE: 1,
STATUS_PLANNED: 2,
STATUS_PROVISIONING: 3,
STATUS_OFFLINE: 4,
STATUS_DECOMMISSIONED: 5,
}

View File

@ -1,19 +1,3 @@
# Circuit statuses
CIRCUIT_STATUS_DEPROVISIONING = 0
CIRCUIT_STATUS_ACTIVE = 1
CIRCUIT_STATUS_PLANNED = 2
CIRCUIT_STATUS_PROVISIONING = 3
CIRCUIT_STATUS_OFFLINE = 4
CIRCUIT_STATUS_DECOMMISSIONED = 5
CIRCUIT_STATUS_CHOICES = [
[CIRCUIT_STATUS_PLANNED, 'Planned'],
[CIRCUIT_STATUS_PROVISIONING, 'Provisioning'],
[CIRCUIT_STATUS_ACTIVE, 'Active'],
[CIRCUIT_STATUS_OFFLINE, 'Offline'],
[CIRCUIT_STATUS_DEPROVISIONING, 'Deprovisioning'],
[CIRCUIT_STATUS_DECOMMISSIONED, 'Decommissioned'],
]
# CircuitTermination sides # CircuitTermination sides
TERM_SIDE_A = 'A' TERM_SIDE_A = 'A'
TERM_SIDE_Z = 'Z' TERM_SIDE_Z = 'Z'

View File

@ -5,6 +5,7 @@ from dcim.models import Region, Site
from extras.filters import CustomFieldFilterSet from extras.filters import CustomFieldFilterSet
from tenancy.filtersets import TenancyFilterSet from tenancy.filtersets import TenancyFilterSet
from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter
from .choices import *
from .constants import * from .constants import *
from .models import Circuit, CircuitTermination, CircuitType, Provider from .models import Circuit, CircuitTermination, CircuitType, Provider
@ -84,7 +85,7 @@ class CircuitFilter(CustomFieldFilterSet, TenancyFilterSet):
label='Circuit type (slug)', label='Circuit type (slug)',
) )
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=CIRCUIT_STATUS_CHOICES, choices=CircuitStatusChoices,
null_value=None null_value=None
) )
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(

View File

@ -9,6 +9,7 @@ from utilities.forms import (
APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField, APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField,
FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple
) )
from .choices import CircuitStatusChoices
from .constants import * from .constants import *
from .models import Circuit, CircuitTermination, CircuitType, Provider from .models import Circuit, CircuitTermination, CircuitType, Provider
@ -194,7 +195,7 @@ class CircuitCSVForm(forms.ModelForm):
} }
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=CIRCUIT_STATUS_CHOICES, choices=CircuitStatusChoices,
required=False, required=False,
help_text='Operational status' help_text='Operational status'
) )
@ -235,7 +236,7 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
) )
) )
status = forms.ChoiceField( status = forms.ChoiceField(
choices=add_blank_choice(CIRCUIT_STATUS_CHOICES), choices=add_blank_choice(CircuitStatusChoices),
required=False, required=False,
initial='', initial='',
widget=StaticSelect2() widget=StaticSelect2()
@ -292,7 +293,7 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm
) )
) )
status = forms.MultipleChoiceField( status = forms.MultipleChoiceField(
choices=CIRCUIT_STATUS_CHOICES, choices=CircuitStatusChoices,
required=False, required=False,
widget=StaticSelect2Multiple() widget=StaticSelect2Multiple()
) )

View File

@ -0,0 +1,37 @@
# Generated by Django 2.2.6 on 2019-11-07 03:36
from django.db import migrations, models
CIRCUIT_STATUS_CHOICES = (
(0, 'deprovisioning'),
(1, 'active'),
(2, 'planned'),
(3, 'provisioning'),
(4, 'offline'),
(5, 'decommissioned')
)
def circuit_status_to_slug(apps, schema_editor):
Circuit = apps.get_model('circuits', 'Circuit')
for id, slug in CIRCUIT_STATUS_CHOICES:
Circuit.objects.filter(status=str(id)).update(status=slug)
class Migration(migrations.Migration):
dependencies = [
('circuits', '0015_custom_tag_models'),
]
operations = [
migrations.AlterField(
model_name='circuit',
name='status',
field=models.CharField(default='active', max_length=50),
),
migrations.RunPython(
code=circuit_status_to_slug
)
]

View File

@ -9,6 +9,7 @@ from dcim.models import CableTermination
from extras.models import CustomFieldModel, ObjectChange, TaggedItem from extras.models import CustomFieldModel, ObjectChange, TaggedItem
from utilities.models import ChangeLoggedModel from utilities.models import ChangeLoggedModel
from utilities.utils import serialize_object from utilities.utils import serialize_object
from .choices import *
from .constants import * from .constants import *
@ -132,9 +133,10 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
on_delete=models.PROTECT, on_delete=models.PROTECT,
related_name='circuits' related_name='circuits'
) )
status = models.PositiveSmallIntegerField( status = models.CharField(
choices=CIRCUIT_STATUS_CHOICES, max_length=50,
default=CIRCUIT_STATUS_ACTIVE choices=CircuitStatusChoices,
default=CircuitStatusChoices.STATUS_ACTIVE
) )
tenant = models.ForeignKey( tenant = models.ForeignKey(
to='tenancy.Tenant', to='tenancy.Tenant',
@ -171,6 +173,15 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments', 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
] ]
STATUS_CLASS_MAP = {
CircuitStatusChoices.STATUS_DEPROVISIONING: 'warning',
CircuitStatusChoices.STATUS_ACTIVE: 'success',
CircuitStatusChoices.STATUS_PLANNED: 'info',
CircuitStatusChoices.STATUS_PROVISIONING: 'primary',
CircuitStatusChoices.STATUS_OFFLINE: 'danger',
CircuitStatusChoices.STATUS_DECOMMISSIONED: 'default',
}
class Meta: class Meta:
ordering = ['provider', 'cid'] ordering = ['provider', 'cid']
unique_together = ['provider', 'cid'] unique_together = ['provider', 'cid']
@ -195,7 +206,7 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
) )
def get_status_class(self): def get_status_class(self):
return STATUS_CLASSES[self.status] return self.STATUS_CLASS_MAP.get(self.status)
def _get_termination(self, side): def _get_termination(self, side):
for ct in self.terminations.all(): for ct in self.terminations.all():

View File

@ -1,9 +1,10 @@
from django.urls import reverse from django.urls import reverse
from rest_framework import status from rest_framework import status
from circuits.constants import CIRCUIT_STATUS_ACTIVE, TERM_SIDE_A, TERM_SIDE_Z from circuits.choices import CircuitStatusChoices
from circuits.constants import TERM_SIDE_A, TERM_SIDE_Z
from circuits.models import Circuit, CircuitTermination, CircuitType, Provider from circuits.models import Circuit, CircuitTermination, CircuitType, Provider
from dcim.models import Device, DeviceRole, DeviceType, Interface, Manufacturer, Site from dcim.models import Site
from extras.constants import GRAPH_TYPE_PROVIDER from extras.constants import GRAPH_TYPE_PROVIDER
from extras.models import Graph from extras.models import Graph
from utilities.testing import APITestCase from utilities.testing import APITestCase
@ -250,7 +251,7 @@ class CircuitTest(APITestCase):
'cid': 'TEST0004', 'cid': 'TEST0004',
'provider': self.provider1.pk, 'provider': self.provider1.pk,
'type': self.circuittype1.pk, 'type': self.circuittype1.pk,
'status': CIRCUIT_STATUS_ACTIVE, 'status': CircuitStatusChoices.STATUS_ACTIVE,
} }
url = reverse('circuits-api:circuit-list') url = reverse('circuits-api:circuit-list')
@ -270,19 +271,19 @@ class CircuitTest(APITestCase):
'cid': 'TEST0004', 'cid': 'TEST0004',
'provider': self.provider1.pk, 'provider': self.provider1.pk,
'type': self.circuittype1.pk, 'type': self.circuittype1.pk,
'status': CIRCUIT_STATUS_ACTIVE, 'status': CircuitStatusChoices.STATUS_ACTIVE,
}, },
{ {
'cid': 'TEST0005', 'cid': 'TEST0005',
'provider': self.provider1.pk, 'provider': self.provider1.pk,
'type': self.circuittype1.pk, 'type': self.circuittype1.pk,
'status': CIRCUIT_STATUS_ACTIVE, 'status': CircuitStatusChoices.STATUS_ACTIVE,
}, },
{ {
'cid': 'TEST0006', 'cid': 'TEST0006',
'provider': self.provider1.pk, 'provider': self.provider1.pk,
'type': self.circuittype1.pk, 'type': self.circuittype1.pk,
'status': CIRCUIT_STATUS_ACTIVE, 'status': CircuitStatusChoices.STATUS_ACTIVE,
}, },
] ]

View File

@ -3,7 +3,7 @@ class ChoiceSetMeta(type):
Metaclass for ChoiceSet Metaclass for ChoiceSet
""" """
def __call__(cls, *args, **kwargs): def __call__(cls, *args, **kwargs):
# Django will check if a choices value is callable, and if so assume that it returns an iterable # Django will check if a 'choices' value is callable, and if so assume that it returns an iterable
return getattr(cls, 'CHOICES', ()) return getattr(cls, 'CHOICES', ())
def __iter__(cls): def __iter__(cls):