From 5c95927a43bf2e22eeeb3472f966ca7f06d09792 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 21 Nov 2019 22:54:01 -0500 Subject: [PATCH] Site.status to slug (#3569) --- netbox/dcim/api/serializers.py | 2 +- netbox/dcim/choices.py | 23 +++++++++++++++++++ netbox/dcim/constants.py | 10 -------- netbox/dcim/filters.py | 2 +- netbox/dcim/forms.py | 6 ++--- .../dcim/migrations/0078_3569_site_fields.py | 20 ++++++++++++++++ netbox/dcim/models.py | 15 ++++++++---- netbox/dcim/tests/test_api.py | 10 ++++---- 8 files changed, 64 insertions(+), 24 deletions(-) diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index bd61f2a9b..5b9c26876 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -68,7 +68,7 @@ class RegionSerializer(serializers.ModelSerializer): class SiteSerializer(TaggitSerializer, CustomFieldModelSerializer): - status = ChoiceField(choices=SITE_STATUS_CHOICES, required=False) + status = ChoiceField(choices=SiteStatusChoices, required=False) region = NestedRegionSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True) time_zone = TimeZoneField(required=False) diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index c5c0c7707..ac161daf8 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -1,6 +1,29 @@ from utilities.choices import ChoiceSet +# +# Sites +# + +class SiteStatusChoices(ChoiceSet): + + STATUS_ACTIVE = 'active' + STATUS_PLANNED = 'planned' + STATUS_RETIRED = 'retired' + + CHOICES = ( + (STATUS_ACTIVE, 'Active'), + (STATUS_PLANNED, 'Planned'), + (STATUS_RETIRED, 'Retired'), + ) + + LEGACY_MAP = { + STATUS_ACTIVE: 1, + STATUS_PLANNED: 2, + STATUS_RETIRED: 4, + } + + # # Racks # diff --git a/netbox/dcim/constants.py b/netbox/dcim/constants.py index 72fec872d..71fbd6cd2 100644 --- a/netbox/dcim/constants.py +++ b/netbox/dcim/constants.py @@ -79,16 +79,6 @@ DEVICE_STATUS_CHOICES = [ [DEVICE_STATUS_DECOMMISSIONING, 'Decommissioning'], ] -# 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/rack statuses STATUS_CLASSES = { 0: 'warning', diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 610a05bd9..4620ea17a 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -49,7 +49,7 @@ class SiteFilter(TenancyFilterSet, CustomFieldFilterSet): label='Search', ) status = django_filters.MultipleChoiceFilter( - choices=SITE_STATUS_CHOICES, + choices=SiteStatusChoices, null_value=None ) region_id = TreeNodeMultipleChoiceFilter( diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 1ea8b2571..15dc79ec5 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -223,7 +223,7 @@ class SiteForm(BootstrapMixin, TenancyForm, CustomFieldForm): class SiteCSVForm(forms.ModelForm): status = CSVChoiceField( - choices=SITE_STATUS_CHOICES, + choices=SiteStatusChoices, required=False, help_text='Operational status' ) @@ -262,7 +262,7 @@ class SiteBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor widget=forms.MultipleHiddenInput ) status = forms.ChoiceField( - choices=add_blank_choice(SITE_STATUS_CHOICES), + choices=add_blank_choice(SiteStatusChoices), required=False, initial='', widget=StaticSelect2() @@ -311,7 +311,7 @@ class SiteFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): label='Search' ) status = forms.MultipleChoiceField( - choices=SITE_STATUS_CHOICES, + choices=SiteStatusChoices, required=False, widget=StaticSelect2Multiple() ) diff --git a/netbox/dcim/migrations/0078_3569_site_fields.py b/netbox/dcim/migrations/0078_3569_site_fields.py index 0826f7f78..502ad6214 100644 --- a/netbox/dcim/migrations/0078_3569_site_fields.py +++ b/netbox/dcim/migrations/0078_3569_site_fields.py @@ -1,5 +1,17 @@ from django.db import migrations, models +SITE_STATUS_CHOICES = ( + (1, 'active'), + (2, 'planned'), + (4, 'retired'), +) + + +def site_status_to_slug(apps, schema_editor): + Site = apps.get_model('dcim', 'Site') + for id, slug in SITE_STATUS_CHOICES: + Site.objects.filter(status=str(id)).update(status=slug) + class Migration(migrations.Migration): atomic = False @@ -9,4 +21,12 @@ class Migration(migrations.Migration): ] operations = [ + migrations.AlterField( + model_name='site', + name='status', + field=models.CharField(default='active', max_length=50), + ), + migrations.RunPython( + code=site_status_to_slug + ), ] diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 6ca145d72..c8d9c8250 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -245,9 +245,10 @@ class Site(ChangeLoggedModel, CustomFieldModel): slug = models.SlugField( unique=True ) - status = models.PositiveSmallIntegerField( - choices=SITE_STATUS_CHOICES, - default=SITE_STATUS_ACTIVE + status = models.CharField( + max_length=50, + choices=SiteStatusChoices, + default=SiteStatusChoices.STATUS_ACTIVE ) region = models.ForeignKey( to='dcim.Region', @@ -331,6 +332,12 @@ class Site(ChangeLoggedModel, CustomFieldModel): 'shipping_address', 'latitude', 'longitude', 'contact_name', 'contact_phone', 'contact_email', 'comments', ] + STATUS_CLASS_MAP = { + SiteStatusChoices.STATUS_ACTIVE: 'success', + SiteStatusChoices.STATUS_PLANNED: 'info', + SiteStatusChoices.STATUS_RETIRED: 'danger', + } + class Meta: ordering = ['name'] @@ -362,7 +369,7 @@ class Site(ChangeLoggedModel, CustomFieldModel): ) def get_status_class(self): - return STATUS_CLASSES[self.status] + return self.STATUS_CLASS_MAP.get(self.status) # diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 17cbe9e6d..466b40b37 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -3,7 +3,7 @@ from netaddr import IPNetwork from rest_framework import status from circuits.models import Circuit, CircuitTermination, CircuitType, Provider -from dcim.choices import InterfaceModeChoices, SubdeviceRoleChoices +from dcim.choices import * from dcim.constants import * from dcim.models import ( Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay, @@ -181,7 +181,7 @@ class SiteTest(APITestCase): 'name': 'Test Site 4', 'slug': 'test-site-4', 'region': self.region1.pk, - 'status': SITE_STATUS_ACTIVE, + 'status': SiteStatusChoices.STATUS_ACTIVE, } url = reverse('dcim-api:site-list') @@ -201,19 +201,19 @@ class SiteTest(APITestCase): 'name': 'Test Site 4', 'slug': 'test-site-4', 'region': self.region1.pk, - 'status': SITE_STATUS_ACTIVE, + 'status': SiteStatusChoices.STATUS_ACTIVE, }, { 'name': 'Test Site 5', 'slug': 'test-site-5', 'region': self.region1.pk, - 'status': SITE_STATUS_ACTIVE, + 'status': SiteStatusChoices.STATUS_ACTIVE, }, { 'name': 'Test Site 6', 'slug': 'test-site-6', 'region': self.region1.pk, - 'status': SITE_STATUS_ACTIVE, + 'status': SiteStatusChoices.STATUS_ACTIVE, }, ]