Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace API integer API choice values with slugs #3732

Merged
merged 48 commits into from
Dec 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
a2a6b75
Introduce ChoiceSet class for field choices
jeremystretch Nov 7, 2019
e09ad69
Circuit.status (#3569)
jeremystretch Nov 7, 2019
62b4549
Convert all DCIM choice classes to ChoiceSets
jeremystretch Nov 16, 2019
8d27b62
Rack.status to slug (#3569)
jeremystretch Nov 16, 2019
07aa036
Convert RACK_WIDTH_CHOICES to ChoiceSet
jeremystretch Nov 16, 2019
e1e09bf
Correct Rack.type migration logic
jeremystretch Nov 16, 2019
c79c29e
Rack.status to slug (#3569)
jeremystretch Nov 16, 2019
a8db07e
Device.face to slug (#3569)
jeremystretch Nov 17, 2019
88b8cf3
Tweak migrations to handle NULL values
jeremystretch Nov 19, 2019
4f0d82a
Standardize migration names for #3569
jeremystretch Nov 19, 2019
fbd12e1
Create a separate migration for each field
jeremystretch Nov 19, 2019
afd82fd
DeviceType.subdevice_role to slug (#3569)
jeremystretch Nov 19, 2019
4e2863e
Move CircuitTermination.term_side choices to a ChoiceSet
jeremystretch Nov 22, 2019
180d3d0
Resolved migration discrepancies when dealing with NULL values
jeremystretch Nov 22, 2019
5f5081f
Interface.type to slug (#3569)
jeremystretch Nov 22, 2019
f93cd17
Consolidate #3569 field migrations by model
jeremystretch Nov 22, 2019
3fa4cea
Interface.mode to slug (#3569)
jeremystretch Nov 22, 2019
5c95927
Site.status to slug (#3569)
jeremystretch Nov 22, 2019
bcc34f6
Device.face to slug (#3569)
jeremystretch Nov 26, 2019
dead5b4
Front/RearPort.type to slug (#3569)
jeremystretch Nov 26, 2019
79a40e2
Cable.type to slug (#3569)
jeremystretch Nov 26, 2019
4846557
Cable.length_unit to slug (#3569)
jeremystretch Nov 26, 2019
9872a46
Rack.outer_unit to slug (#3569)
jeremystretch Nov 26, 2019
62494f2
PowerFeed.type to slug (#3569)
jeremystretch Nov 26, 2019
bb8b012
PowerFeed.supply to slug (#3569)
jeremystretch Nov 26, 2019
2dc07ca
PowerFeed.phase to slug (#3569)
jeremystretch Nov 26, 2019
8c7f6c6
PowerFeed.status to slug (#3569)
jeremystretch Nov 26, 2019
21fe590
PowerOutlet.feed_leg to slug (#3569)
jeremystretch Nov 28, 2019
929c064
Prefix.status to slug (#3569)
jeremystretch Nov 28, 2019
ba8f324
IPAddress.status to slug (#3569)
jeremystretch Nov 28, 2019
14a7a33
IPAddress.role to slug (#3569)
jeremystretch Nov 28, 2019
213bd15
VLAN.status to slug (#3569)
jeremystretch Nov 28, 2019
4ecbfc4
Service.protocol to slug (#3569)
jeremystretch Nov 28, 2019
ca11b9a
VirtualMachine.status to slug
jeremystretch Dec 5, 2019
3ff22be
CustomField.type to slug
jeremystretch Dec 5, 2019
bfea77b
CustomField.filter_logic to slug
jeremystretch Dec 5, 2019
7a3c725
Convert BUTTON_CLASS_CHOICES to a ChoiceSet
jeremystretch Dec 5, 2019
4e1ee27
Extend CustomField migration to update CustomFieldChoice.field.limit_…
jeremystretch Dec 5, 2019
8efde81
Fix PowerFeed field defaults
jeremystretch Dec 5, 2019
2bcbcd3
ObjectChange.action to slug (#3569)
jeremystretch Dec 5, 2019
a2b0da2
Fix changelog table action labels
jeremystretch Dec 5, 2019
33890e6
Remain consistent with original action strings (e.g. 'created' instea…
jeremystretch Dec 5, 2019
2583823
Delete obsolete user action types
jeremystretch Dec 5, 2019
89e720c
ExportTemplate.template_language to slug (#3569)
jeremystretch Dec 5, 2019
5d772d7
Webhook.http_content_type to slug (#3569)
jeremystretch Dec 5, 2019
edbf562
Annotate all migration operation lists
jeremystretch Dec 5, 2019
17898a4
Merge branch 'develop-2.7' into 3569-api-choice-slugs
jeremystretch Dec 5, 2019
b0c0adf
Adapt device component import forms from #3711
jeremystretch Dec 5, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions netbox/circuits/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from rest_framework import serializers
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 dcim.api.nested_serializers import NestedCableSerializer, NestedSiteSerializer
from dcim.api.serializers import ConnectedEndpointSerializer
Expand Down Expand Up @@ -41,7 +41,7 @@ class Meta:

class CircuitSerializer(TaggitSerializer, CustomFieldModelSerializer):
provider = NestedProviderSerializer()
status = ChoiceField(choices=CIRCUIT_STATUS_CHOICES, required=False)
status = ChoiceField(choices=CircuitStatusChoices, required=False)
type = NestedCircuitTypeSerializer()
tenant = NestedTenantSerializer(required=False, allow_null=True)
tags = TagListSerializerField(required=False)
Expand Down
48 changes: 48 additions & 0 deletions netbox/circuits/choices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from utilities.choices import ChoiceSet


#
# Circuits
#

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,
}


#
# CircuitTerminations
#

class CircuitTerminationSideChoices(ChoiceSet):

SIDE_A = 'A'
SIDE_Z = 'Z'

CHOICES = (
(SIDE_A, 'A'),
(SIDE_Z, 'Z')
)
23 changes: 0 additions & 23 deletions netbox/circuits/constants.py

This file was deleted.

4 changes: 2 additions & 2 deletions netbox/circuits/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from extras.filters import CustomFieldFilterSet, CreatedUpdatedFilterSet
from tenancy.filtersets import TenancyFilterSet
from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter
from .constants import *
from .choices import *
from .models import Circuit, CircuitTermination, CircuitType, Provider


Expand Down Expand Up @@ -84,7 +84,7 @@ class CircuitFilter(CustomFieldFilterSet, TenancyFilterSet, CreatedUpdatedFilter
label='Circuit type (slug)',
)
status = django_filters.MultipleChoiceFilter(
choices=CIRCUIT_STATUS_CHOICES,
choices=CircuitStatusChoices,
null_value=None
)
site_id = django_filters.ModelMultipleChoiceFilter(
Expand Down
8 changes: 4 additions & 4 deletions netbox/circuits/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField,
FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple
)
from .constants import *
from .choices import CircuitStatusChoices
from .models import Circuit, CircuitTermination, CircuitType, Provider


Expand Down Expand Up @@ -194,7 +194,7 @@ class CircuitCSVForm(forms.ModelForm):
}
)
status = CSVChoiceField(
choices=CIRCUIT_STATUS_CHOICES,
choices=CircuitStatusChoices,
required=False,
help_text='Operational status'
)
Expand Down Expand Up @@ -235,7 +235,7 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
)
)
status = forms.ChoiceField(
choices=add_blank_choice(CIRCUIT_STATUS_CHOICES),
choices=add_blank_choice(CircuitStatusChoices),
required=False,
initial='',
widget=StaticSelect2()
Expand Down Expand Up @@ -292,7 +292,7 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm
)
)
status = forms.MultipleChoiceField(
choices=CIRCUIT_STATUS_CHOICES,
choices=CircuitStatusChoices,
required=False,
widget=StaticSelect2Multiple()
)
Expand Down
39 changes: 39 additions & 0 deletions netbox/circuits/migrations/0016_3569_circuit_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
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):
atomic = False

dependencies = [
('circuits', '0015_custom_tag_models'),
]

operations = [

# Circuit.status
migrations.AlterField(
model_name='circuit',
name='status',
field=models.CharField(default='active', max_length=50),
),
migrations.RunPython(
code=circuit_status_to_slug
),

]
24 changes: 17 additions & 7 deletions netbox/circuits/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
from django.urls import reverse
from taggit.managers import TaggableManager

from dcim.constants import CONNECTION_STATUS_CHOICES, STATUS_CLASSES
from dcim.constants import CONNECTION_STATUS_CHOICES
from dcim.fields import ASNField
from dcim.models import CableTermination
from extras.models import CustomFieldModel, ObjectChange, TaggedItem
from utilities.models import ChangeLoggedModel
from utilities.utils import serialize_object
from .constants import *
from .choices import *


class Provider(ChangeLoggedModel, CustomFieldModel):
Expand Down Expand Up @@ -132,9 +132,10 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
on_delete=models.PROTECT,
related_name='circuits'
)
status = models.PositiveSmallIntegerField(
choices=CIRCUIT_STATUS_CHOICES,
default=CIRCUIT_STATUS_ACTIVE
status = models.CharField(
max_length=50,
choices=CircuitStatusChoices,
default=CircuitStatusChoices.STATUS_ACTIVE
)
tenant = models.ForeignKey(
to='tenancy.Tenant',
Expand Down Expand Up @@ -171,6 +172,15 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
'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:
ordering = ['provider', 'cid']
unique_together = ['provider', 'cid']
Expand All @@ -195,7 +205,7 @@ def to_csv(self):
)

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

def _get_termination(self, side):
for ct in self.terminations.all():
Expand All @@ -220,7 +230,7 @@ class CircuitTermination(CableTermination):
)
term_side = models.CharField(
max_length=1,
choices=TERM_SIDE_CHOICES,
choices=CircuitTerminationSideChoices,
verbose_name='Termination'
)
site = models.ForeignKey(
Expand Down
41 changes: 28 additions & 13 deletions netbox/circuits/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from django.urls import reverse
from rest_framework import status

from circuits.constants import CIRCUIT_STATUS_ACTIVE, TERM_SIDE_A, TERM_SIDE_Z
from circuits.choices import *
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.models import Graph
from utilities.testing import APITestCase
Expand Down Expand Up @@ -250,7 +250,7 @@ def test_create_circuit(self):
'cid': 'TEST0004',
'provider': self.provider1.pk,
'type': self.circuittype1.pk,
'status': CIRCUIT_STATUS_ACTIVE,
'status': CircuitStatusChoices.STATUS_ACTIVE,
}

url = reverse('circuits-api:circuit-list')
Expand All @@ -270,19 +270,19 @@ def test_create_circuit_bulk(self):
'cid': 'TEST0004',
'provider': self.provider1.pk,
'type': self.circuittype1.pk,
'status': CIRCUIT_STATUS_ACTIVE,
'status': CircuitStatusChoices.STATUS_ACTIVE,
},
{
'cid': 'TEST0005',
'provider': self.provider1.pk,
'type': self.circuittype1.pk,
'status': CIRCUIT_STATUS_ACTIVE,
'status': CircuitStatusChoices.STATUS_ACTIVE,
},
{
'cid': 'TEST0006',
'provider': self.provider1.pk,
'type': self.circuittype1.pk,
'status': CIRCUIT_STATUS_ACTIVE,
'status': CircuitStatusChoices.STATUS_ACTIVE,
},
]

Expand Down Expand Up @@ -336,16 +336,28 @@ def setUp(self):
self.circuit2 = Circuit.objects.create(cid='TEST0002', provider=provider, type=circuittype)
self.circuit3 = Circuit.objects.create(cid='TEST0003', provider=provider, type=circuittype)
self.circuittermination1 = CircuitTermination.objects.create(
circuit=self.circuit1, term_side=TERM_SIDE_A, site=self.site1, port_speed=1000000
circuit=self.circuit1,
term_side=CircuitTerminationSideChoices.SIDE_A,
site=self.site1,
port_speed=1000000
)
self.circuittermination2 = CircuitTermination.objects.create(
circuit=self.circuit1, term_side=TERM_SIDE_Z, site=self.site2, port_speed=1000000
circuit=self.circuit1,
term_side=CircuitTerminationSideChoices.SIDE_Z,
site=self.site2,
port_speed=1000000
)
self.circuittermination3 = CircuitTermination.objects.create(
circuit=self.circuit2, term_side=TERM_SIDE_A, site=self.site1, port_speed=1000000
circuit=self.circuit2,
term_side=CircuitTerminationSideChoices.SIDE_A,
site=self.site1,
port_speed=1000000
)
self.circuittermination4 = CircuitTermination.objects.create(
circuit=self.circuit2, term_side=TERM_SIDE_Z, site=self.site2, port_speed=1000000
circuit=self.circuit2,
term_side=CircuitTerminationSideChoices.SIDE_Z,
site=self.site2,
port_speed=1000000
)

def test_get_circuittermination(self):
Expand All @@ -366,7 +378,7 @@ def test_create_circuittermination(self):

data = {
'circuit': self.circuit3.pk,
'term_side': TERM_SIDE_A,
'term_side': CircuitTerminationSideChoices.SIDE_A,
'site': self.site1.pk,
'port_speed': 1000000,
}
Expand All @@ -385,12 +397,15 @@ def test_create_circuittermination(self):
def test_update_circuittermination(self):

circuittermination5 = CircuitTermination.objects.create(
circuit=self.circuit3, term_side=TERM_SIDE_A, site=self.site1, port_speed=1000000
circuit=self.circuit3,
term_side=CircuitTerminationSideChoices.SIDE_A,
site=self.site1,
port_speed=1000000
)

data = {
'circuit': self.circuit3.pk,
'term_side': TERM_SIDE_Z,
'term_side': CircuitTerminationSideChoices.SIDE_Z,
'site': self.site2.pk,
'port_speed': 1000000,
}
Expand Down
14 changes: 9 additions & 5 deletions netbox/circuits/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
)
from . import filters, forms, tables
from .constants import TERM_SIDE_A, TERM_SIDE_Z
from .choices import CircuitTerminationSideChoices
from .models import Circuit, CircuitTermination, CircuitType, Provider


Expand Down Expand Up @@ -151,12 +151,12 @@ def get(self, request, pk):
termination_a = CircuitTermination.objects.prefetch_related(
'site__region', 'connected_endpoint__device'
).filter(
circuit=circuit, term_side=TERM_SIDE_A
circuit=circuit, term_side=CircuitTerminationSideChoices.SIDE_A
).first()
termination_z = CircuitTermination.objects.prefetch_related(
'site__region', 'connected_endpoint__device'
).filter(
circuit=circuit, term_side=TERM_SIDE_Z
circuit=circuit, term_side=CircuitTerminationSideChoices.SIDE_Z
).first()

return render(request, 'circuits/circuit.html', {
Expand Down Expand Up @@ -212,8 +212,12 @@ class CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
def circuit_terminations_swap(request, pk):

circuit = get_object_or_404(Circuit, pk=pk)
termination_a = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_A).first()
termination_z = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_Z).first()
termination_a = CircuitTermination.objects.filter(
circuit=circuit, term_side=CircuitTerminationSideChoices.SIDE_A
).first()
termination_z = CircuitTermination.objects.filter(
circuit=circuit, term_side=CircuitTerminationSideChoices.SIDE_Z
).first()
if not termination_a and not termination_z:
messages.error(request, "No terminations have been defined for circuit {}.".format(circuit))
return redirect('circuits:circuit', pk=circuit.pk)
Expand Down
Loading