Просмотр исходного кода

Merge pull request #4359 from netbox-community/3416-remove-API-choices

Closes #3416: Remove API _choices endpoints
Jeremy Stretch 6 лет назад
Родитель
Сommit
16bc262a4f

+ 25 - 51
docs/api/overview.md

@@ -187,37 +187,6 @@ GET /api/ipam/prefixes/13980/?brief=1
 
 
 The brief format is supported for both lists and individual objects.
 The brief format is supported for both lists and individual objects.
 
 
-### Static Choice Fields
-
-Some model fields, such as the `status` field in the above example, utilize static integers corresponding to static choices. The available choices can be retrieved from the read-only `_choices` endpoint within each app. A specific `model:field` tuple may optionally be specified in the URL.
-
-Each choice includes a human-friendly label and its corresponding numeric value. For example, `GET /api/ipam/_choices/prefix:status/` will return:
-
-```
-[
-    {
-        "value": 0,
-        "label": "Container"
-    },
-    {
-        "value": 1,
-        "label": "Active"
-    },
-    {
-        "value": 2,
-        "label": "Reserved"
-    },
-    {
-        "value": 3,
-        "label": "Deprecated"
-    }
-]
-```
-
-Thus, to set a prefix's status to "Reserved," it would be assigned the integer `2`.
-
-A request for `GET /api/ipam/_choices/` will return choices for _all_ fields belonging to models within the IPAM app.
-
 ## Pagination
 ## Pagination
 
 
 API responses which contain a list of objects (for example, a request to `/api/dcim/devices/`) will be paginated to avoid unnecessary overhead. The root JSON object will contain the following attributes:
 API responses which contain a list of objects (for example, a request to `/api/dcim/devices/`) will be paginated to avoid unnecessary overhead. The root JSON object will contain the following attributes:
@@ -280,27 +249,32 @@ A list of objects retrieved via the API can be filtered by passing one or more q
 GET /api/ipam/prefixes/?status=1
 GET /api/ipam/prefixes/?status=1
 ```
 ```
 
 
-The choices available for fixed choice fields such as `status` are exposed in the API under a special `_choices` endpoint for each NetBox app. For example, the available choices for `Prefix.status` are listed at `/api/ipam/_choices/` under the key `prefix:status`:
+The choices available for fixed choice fields such as `status` can be retrieved by sending an `OPTIONS` API request for the desired endpoint:
+
+```no-highlight
+$ curl -s -X OPTIONS \
+-H "Content-Type: application/json" \
+-H "Accept: application/json; indent=4" \
+http://localhost:8000/api/ipam/prefixes/ | jq ".actions.POST.status.choices"
+[
+  {
+    "value": "container",
+    "display_name": "Container"
+  },
+  {
+    "value": "active",
+    "display_name": "Active"
+  },
+  {
+    "value": "reserved",
+    "display_name": "Reserved"
+  },
+  {
+    "value": "deprecated",
+    "display_name": "Deprecated"
+  }
+]
 
 
-```
-"prefix:status": [
-    {
-        "label": "Container",
-        "value": 0
-    },
-    {
-        "label": "Active",
-        "value": 1
-    },
-    {
-        "label": "Reserved",
-        "value": 2
-    },
-    {
-        "label": "Deprecated",
-        "value": 3
-    }
-],
 ```
 ```
 
 
 For most fields, when a filter is passed multiple times, objects matching _any_ of the provided values will be returned. For example, `GET /api/dcim/sites/?name=Foo&name=Bar` will return all sites named "Foo" _or_ "Bar". The exception to this rule is ManyToManyFields which may have multiple values assigned. Tags are the most common example of a ManyToManyField. For example, `GET /api/dcim/sites/?tag=foo&tag=bar` will return only sites tagged with both "foo" _and_ "bar".
 For most fields, when a filter is passed multiple times, objects matching _any_ of the provided values will be returned. For example, `GET /api/dcim/sites/?name=Foo&name=Bar` will return all sites named "Foo" _or_ "Bar". The exception to this rule is ManyToManyFields which may have multiple values assigned. Tags are the most common example of a ManyToManyField. For example, `GET /api/dcim/sites/?tag=foo&tag=bar` will return only sites tagged with both "foo" _and_ "bar".

+ 0 - 3
netbox/circuits/api/urls.py

@@ -14,9 +14,6 @@ class CircuitsRootView(routers.APIRootView):
 router = routers.DefaultRouter()
 router = routers.DefaultRouter()
 router.APIRootView = CircuitsRootView
 router.APIRootView = CircuitsRootView
 
 
-# Field choices
-router.register('_choices', views.CircuitsFieldChoicesViewSet, basename='field-choice')
-
 # Providers
 # Providers
 router.register('providers', views.ProviderViewSet)
 router.register('providers', views.ProviderViewSet)
 
 

+ 1 - 12
netbox/circuits/api/views.py

@@ -8,21 +8,10 @@ from circuits.models import Provider, CircuitTermination, CircuitType, Circuit
 from extras.api.serializers import RenderedGraphSerializer
 from extras.api.serializers import RenderedGraphSerializer
 from extras.api.views import CustomFieldModelViewSet
 from extras.api.views import CustomFieldModelViewSet
 from extras.models import Graph
 from extras.models import Graph
-from utilities.api import FieldChoicesViewSet, ModelViewSet
+from utilities.api import ModelViewSet
 from . import serializers
 from . import serializers
 
 
 
 
-#
-# Field choices
-#
-
-class CircuitsFieldChoicesViewSet(FieldChoicesViewSet):
-    fields = (
-        (serializers.CircuitSerializer, ['status']),
-        (serializers.CircuitTerminationSerializer, ['term_side']),
-    )
-
-
 #
 #
 # Providers
 # Providers
 #
 #

+ 1 - 14
netbox/circuits/tests/test_api.py

@@ -6,7 +6,7 @@ from circuits.choices import *
 from circuits.models import Circuit, CircuitTermination, CircuitType, Provider
 from circuits.models import Circuit, CircuitTermination, CircuitType, Provider
 from dcim.models import Site
 from dcim.models import Site
 from extras.models import Graph
 from extras.models import Graph
-from utilities.testing import APITestCase, choices_to_dict
+from utilities.testing import APITestCase
 
 
 
 
 class AppTest(APITestCase):
 class AppTest(APITestCase):
@@ -18,19 +18,6 @@ class AppTest(APITestCase):
 
 
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
-    def test_choices(self):
-
-        url = reverse('circuits-api:field-choice-list')
-        response = self.client.get(url, **self.header)
-
-        self.assertEqual(response.status_code, 200)
-
-        # Circuit
-        self.assertEqual(choices_to_dict(response.data.get('circuit:status')), CircuitStatusChoices.as_dict())
-
-        # CircuitTermination
-        self.assertEqual(choices_to_dict(response.data.get('circuit-termination:term_side')), CircuitTerminationSideChoices.as_dict())
-
 
 
 class ProviderTest(APITestCase):
 class ProviderTest(APITestCase):
 
 

+ 0 - 3
netbox/dcim/api/urls.py

@@ -14,9 +14,6 @@ class DCIMRootView(routers.APIRootView):
 router = routers.DefaultRouter()
 router = routers.DefaultRouter()
 router.APIRootView = DCIMRootView
 router.APIRootView = DCIMRootView
 
 
-# Field choices
-router.register('_choices', views.DCIMFieldChoicesViewSet, basename='field-choice')
-
 # Sites
 # Sites
 router.register('regions', views.RegionViewSet)
 router.register('regions', views.RegionViewSet)
 router.register('sites', views.SiteViewSet)
 router.register('sites', views.SiteViewSet)

+ 1 - 30
netbox/dcim/api/views.py

@@ -26,7 +26,7 @@ from extras.api.views import CustomFieldModelViewSet
 from extras.models import Graph
 from extras.models import Graph
 from ipam.models import Prefix, VLAN
 from ipam.models import Prefix, VLAN
 from utilities.api import (
 from utilities.api import (
-    get_serializer_for_model, IsAuthenticatedOrLoginNotRequired, FieldChoicesViewSet, ModelViewSet, ServiceUnavailable,
+    get_serializer_for_model, IsAuthenticatedOrLoginNotRequired, ModelViewSet, ServiceUnavailable,
 )
 )
 from utilities.utils import get_subquery
 from utilities.utils import get_subquery
 from virtualization.models import VirtualMachine
 from virtualization.models import VirtualMachine
@@ -34,35 +34,6 @@ from . import serializers
 from .exceptions import MissingFilterException
 from .exceptions import MissingFilterException
 
 
 
 
-#
-# Field choices
-#
-
-class DCIMFieldChoicesViewSet(FieldChoicesViewSet):
-    fields = (
-        (serializers.CableSerializer, ['length_unit', 'status', 'termination_a_type', 'termination_b_type', 'type']),
-        (serializers.ConsolePortSerializer, ['type', 'connection_status']),
-        (serializers.ConsolePortTemplateSerializer, ['type']),
-        (serializers.ConsoleServerPortSerializer, ['type']),
-        (serializers.ConsoleServerPortTemplateSerializer, ['type']),
-        (serializers.DeviceSerializer, ['face', 'status']),
-        (serializers.DeviceTypeSerializer, ['subdevice_role']),
-        (serializers.FrontPortSerializer, ['type']),
-        (serializers.FrontPortTemplateSerializer, ['type']),
-        (serializers.InterfaceSerializer, ['type', 'mode']),
-        (serializers.InterfaceTemplateSerializer, ['type']),
-        (serializers.PowerFeedSerializer, ['phase', 'status', 'supply', 'type']),
-        (serializers.PowerOutletSerializer, ['type', 'feed_leg']),
-        (serializers.PowerOutletTemplateSerializer, ['type', 'feed_leg']),
-        (serializers.PowerPortSerializer, ['type', 'connection_status']),
-        (serializers.PowerPortTemplateSerializer, ['type']),
-        (serializers.RackSerializer, ['outer_unit', 'status', 'type', 'width']),
-        (serializers.RearPortSerializer, ['type']),
-        (serializers.RearPortTemplateSerializer, ['type']),
-        (serializers.SiteSerializer, ['status']),
-    )
-
-
 # Mixins
 # Mixins
 
 
 class CableTraceMixin(object):
 class CableTraceMixin(object):

+ 1 - 74
netbox/dcim/tests/test_api.py

@@ -14,7 +14,7 @@ from dcim.models import (
 )
 )
 from ipam.models import IPAddress, VLAN
 from ipam.models import IPAddress, VLAN
 from extras.models import Graph
 from extras.models import Graph
-from utilities.testing import APITestCase, choices_to_dict
+from utilities.testing import APITestCase
 from virtualization.models import Cluster, ClusterType
 from virtualization.models import Cluster, ClusterType
 
 
 
 
@@ -27,79 +27,6 @@ class AppTest(APITestCase):
 
 
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
-    def test_choices(self):
-
-        url = reverse('dcim-api:field-choice-list')
-        response = self.client.get(url, **self.header)
-
-        self.assertEqual(response.status_code, 200)
-
-        # Cable
-        self.assertEqual(choices_to_dict(response.data.get('cable:length_unit')), CableLengthUnitChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('cable:status')), CableStatusChoices.as_dict())
-        content_types = ContentType.objects.filter(CABLE_TERMINATION_MODELS)
-        cable_termination_choices = {
-            "{}.{}".format(ct.app_label, ct.model): str(ct) for ct in content_types
-        }
-        self.assertEqual(choices_to_dict(response.data.get('cable:termination_a_type')), cable_termination_choices)
-        self.assertEqual(choices_to_dict(response.data.get('cable:termination_b_type')), cable_termination_choices)
-        self.assertEqual(choices_to_dict(response.data.get('cable:type')), CableTypeChoices.as_dict())
-
-        # Console ports
-        self.assertEqual(choices_to_dict(response.data.get('console-port:type')), ConsolePortTypeChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('console-port:connection_status')), dict(CONNECTION_STATUS_CHOICES))
-        self.assertEqual(choices_to_dict(response.data.get('console-port-template:type')), ConsolePortTypeChoices.as_dict())
-
-        # Console server ports
-        self.assertEqual(choices_to_dict(response.data.get('console-server-port:type')), ConsolePortTypeChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('console-server-port-template:type')), ConsolePortTypeChoices.as_dict())
-
-        # Device
-        self.assertEqual(choices_to_dict(response.data.get('device:face')), DeviceFaceChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('device:status')), DeviceStatusChoices.as_dict())
-
-        # Device type
-        self.assertEqual(choices_to_dict(response.data.get('device-type:subdevice_role')), SubdeviceRoleChoices.as_dict())
-
-        # Front ports
-        self.assertEqual(choices_to_dict(response.data.get('front-port:type')), PortTypeChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('front-port-template:type')), PortTypeChoices.as_dict())
-
-        # Interfaces
-        self.assertEqual(choices_to_dict(response.data.get('interface:type')), InterfaceTypeChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('interface:mode')), InterfaceModeChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('interface-template:type')), InterfaceTypeChoices.as_dict())
-
-        # Power feed
-        self.assertEqual(choices_to_dict(response.data.get('power-feed:phase')), PowerFeedPhaseChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('power-feed:status')), PowerFeedStatusChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('power-feed:supply')), PowerFeedSupplyChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('power-feed:type')), PowerFeedTypeChoices.as_dict())
-
-        # Power outlets
-        self.assertEqual(choices_to_dict(response.data.get('power-outlet:type')), PowerOutletTypeChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('power-outlet:feed_leg')), PowerOutletFeedLegChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('power-outlet-template:type')), PowerOutletTypeChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('power-outlet-template:feed_leg')), PowerOutletFeedLegChoices.as_dict())
-
-        # Power ports
-        self.assertEqual(choices_to_dict(response.data.get('power-port:type')), PowerPortTypeChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('power-port:connection_status')), dict(CONNECTION_STATUS_CHOICES))
-        self.assertEqual(choices_to_dict(response.data.get('power-port-template:type')), PowerPortTypeChoices.as_dict())
-
-        # Rack
-        self.assertEqual(choices_to_dict(response.data.get('rack:type')), RackTypeChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('rack:width')), RackWidthChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('rack:status')), RackStatusChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('rack:outer_unit')), RackDimensionUnitChoices.as_dict())
-
-        # Rear ports
-        self.assertEqual(choices_to_dict(response.data.get('rear-port:type')), PortTypeChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('rear-port-template:type')), PortTypeChoices.as_dict())
-
-        # Site
-        self.assertEqual(choices_to_dict(response.data.get('site:status')), SiteStatusChoices.as_dict())
-
 
 
 class RegionTest(APITestCase):
 class RegionTest(APITestCase):
 
 

+ 0 - 3
netbox/extras/api/urls.py

@@ -14,9 +14,6 @@ class ExtrasRootView(routers.APIRootView):
 router = routers.DefaultRouter()
 router = routers.DefaultRouter()
 router.APIRootView = ExtrasRootView
 router.APIRootView = ExtrasRootView
 
 
-# Field choices
-router.register('_choices', views.ExtrasFieldChoicesViewSet, basename='field-choice')
-
 # Custom field choices
 # Custom field choices
 router.register('_custom_field_choices', views.CustomFieldChoicesViewSet, basename='custom-field-choice')
 router.register('_custom_field_choices', views.CustomFieldChoicesViewSet, basename='custom-field-choice')
 
 

+ 1 - 13
netbox/extras/api/views.py

@@ -15,22 +15,10 @@ from extras.models import (
 )
 )
 from extras.reports import get_report, get_reports
 from extras.reports import get_report, get_reports
 from extras.scripts import get_script, get_scripts, run_script
 from extras.scripts import get_script, get_scripts, run_script
-from utilities.api import FieldChoicesViewSet, IsAuthenticatedOrLoginNotRequired, ModelViewSet
+from utilities.api import IsAuthenticatedOrLoginNotRequired, ModelViewSet
 from . import serializers
 from . import serializers
 
 
 
 
-#
-# Field choices
-#
-
-class ExtrasFieldChoicesViewSet(FieldChoicesViewSet):
-    fields = (
-        (serializers.ExportTemplateSerializer, ['template_language']),
-        (serializers.GraphSerializer, ['type', 'template_language']),
-        (serializers.ObjectChangeSerializer, ['action']),
-    )
-
-
 #
 #
 # Custom field choices
 # Custom field choices
 #
 #

+ 1 - 24
netbox/extras/tests/test_api.py

@@ -7,12 +7,10 @@ from rest_framework import status
 
 
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Platform, Rack, RackGroup, RackRole, Region, Site
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Platform, Rack, RackGroup, RackRole, Region, Site
 from extras.api.views import ScriptViewSet
 from extras.api.views import ScriptViewSet
-from extras.choices import *
-from extras.constants import GRAPH_MODELS
 from extras.models import ConfigContext, Graph, ExportTemplate, Tag
 from extras.models import ConfigContext, Graph, ExportTemplate, Tag
 from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
 from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
-from utilities.testing import APITestCase, choices_to_dict
+from utilities.testing import APITestCase
 
 
 
 
 class AppTest(APITestCase):
 class AppTest(APITestCase):
@@ -24,27 +22,6 @@ class AppTest(APITestCase):
 
 
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
-    def test_choices(self):
-
-        url = reverse('extras-api:field-choice-list')
-        response = self.client.get(url, **self.header)
-
-        self.assertEqual(response.status_code, 200)
-
-        # ExportTemplate
-        self.assertEqual(choices_to_dict(response.data.get('export-template:template_language')), TemplateLanguageChoices.as_dict())
-
-        # Graph
-        content_types = ContentType.objects.filter(GRAPH_MODELS)
-        graph_type_choices = {
-            "{}.{}".format(ct.app_label, ct.model): str(ct) for ct in content_types
-        }
-        self.assertEqual(choices_to_dict(response.data.get('graph:type')), graph_type_choices)
-        self.assertEqual(choices_to_dict(response.data.get('graph:template_language')), TemplateLanguageChoices.as_dict())
-
-        # ObjectChange
-        self.assertEqual(choices_to_dict(response.data.get('object-change:action')), ObjectChangeActionChoices.as_dict())
-
 
 
 class GraphTest(APITestCase):
 class GraphTest(APITestCase):
 
 

+ 0 - 3
netbox/ipam/api/urls.py

@@ -14,9 +14,6 @@ class IPAMRootView(routers.APIRootView):
 router = routers.DefaultRouter()
 router = routers.DefaultRouter()
 router.APIRootView = IPAMRootView
 router.APIRootView = IPAMRootView
 
 
-# Field choices
-router.register('_choices', views.IPAMFieldChoicesViewSet, basename='field-choice')
-
 # VRFs
 # VRFs
 router.register('vrfs', views.VRFViewSet)
 router.register('vrfs', views.VRFViewSet)
 
 

+ 1 - 15
netbox/ipam/api/views.py

@@ -10,26 +10,12 @@ from rest_framework.response import Response
 from extras.api.views import CustomFieldModelViewSet
 from extras.api.views import CustomFieldModelViewSet
 from ipam import filters
 from ipam import filters
 from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
 from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
-from utilities.api import FieldChoicesViewSet, ModelViewSet
+from utilities.api import ModelViewSet
 from utilities.constants import ADVISORY_LOCK_KEYS
 from utilities.constants import ADVISORY_LOCK_KEYS
 from utilities.utils import get_subquery
 from utilities.utils import get_subquery
 from . import serializers
 from . import serializers
 
 
 
 
-#
-# Field choices
-#
-
-class IPAMFieldChoicesViewSet(FieldChoicesViewSet):
-    fields = (
-        (serializers.AggregateSerializer, ['family']),
-        (serializers.PrefixSerializer, ['family', 'status']),
-        (serializers.IPAddressSerializer, ['family', 'status', 'role']),
-        (serializers.VLANSerializer, ['status']),
-        (serializers.ServiceSerializer, ['protocol']),
-    )
-
-
 #
 #
 # VRFs
 # VRFs
 #
 #

+ 1 - 26
netbox/ipam/tests/test_api.py

@@ -7,7 +7,7 @@ from rest_framework import status
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
 from ipam.choices import *
 from ipam.choices import *
 from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
 from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
-from utilities.testing import APITestCase, choices_to_dict, disable_warnings
+from utilities.testing import APITestCase, disable_warnings
 
 
 
 
 class AppTest(APITestCase):
 class AppTest(APITestCase):
@@ -19,31 +19,6 @@ class AppTest(APITestCase):
 
 
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
-    def test_choices(self):
-
-        url = reverse('ipam-api:field-choice-list')
-        response = self.client.get(url, **self.header)
-
-        self.assertEqual(response.status_code, 200)
-
-        # Aggregate
-        # self.assertEqual(choices_to_dict(response.data.get('aggregate:family')), )
-
-        # Prefix
-        # self.assertEqual(choices_to_dict(response.data.get('prefix:family')), )
-        self.assertEqual(choices_to_dict(response.data.get('prefix:status')), PrefixStatusChoices.as_dict())
-
-        # IPAddress
-        # self.assertEqual(choices_to_dict(response.data.get('ip-address:family')), )
-        self.assertEqual(choices_to_dict(response.data.get('ip-address:role')), IPAddressRoleChoices.as_dict())
-        self.assertEqual(choices_to_dict(response.data.get('ip-address:status')), IPAddressStatusChoices.as_dict())
-
-        # VLAN
-        self.assertEqual(choices_to_dict(response.data.get('vlan:status')), VLANStatusChoices.as_dict())
-
-        # Service
-        self.assertEqual(choices_to_dict(response.data.get('service:protocol')), ServiceProtocolChoices.as_dict())
-
 
 
 class VRFTest(APITestCase):
 class VRFTest(APITestCase):
 
 

+ 0 - 3
netbox/secrets/api/urls.py

@@ -14,9 +14,6 @@ class SecretsRootView(routers.APIRootView):
 router = routers.DefaultRouter()
 router = routers.DefaultRouter()
 router.APIRootView = SecretsRootView
 router.APIRootView = SecretsRootView
 
 
-# Field choices
-router.register('_choices', views.SecretsFieldChoicesViewSet, basename='field-choice')
-
 # Secrets
 # Secrets
 router.register('secret-roles', views.SecretRoleViewSet)
 router.register('secret-roles', views.SecretRoleViewSet)
 router.register('secrets', views.SecretViewSet)
 router.register('secrets', views.SecretViewSet)

+ 1 - 9
netbox/secrets/api/views.py

@@ -11,7 +11,7 @@ from rest_framework.viewsets import ViewSet
 from secrets import filters
 from secrets import filters
 from secrets.exceptions import InvalidKey
 from secrets.exceptions import InvalidKey
 from secrets.models import Secret, SecretRole, SessionKey, UserKey
 from secrets.models import Secret, SecretRole, SessionKey, UserKey
-from utilities.api import FieldChoicesViewSet, ModelViewSet
+from utilities.api import ModelViewSet
 from . import serializers
 from . import serializers
 
 
 ERR_USERKEY_MISSING = "No UserKey found for the current user."
 ERR_USERKEY_MISSING = "No UserKey found for the current user."
@@ -20,14 +20,6 @@ ERR_PRIVKEY_MISSING = "Private key was not provided."
 ERR_PRIVKEY_INVALID = "Invalid private key."
 ERR_PRIVKEY_INVALID = "Invalid private key."
 
 
 
 
-#
-# Field choices
-#
-
-class SecretsFieldChoicesViewSet(FieldChoicesViewSet):
-    fields = ()
-
-
 #
 #
 # Secret Roles
 # Secret Roles
 #
 #

+ 0 - 7
netbox/secrets/tests/test_api.py

@@ -19,13 +19,6 @@ class AppTest(APITestCase):
 
 
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
-    def test_choices(self):
-
-        url = reverse('secrets-api:field-choice-list')
-        response = self.client.get(url, **self.header)
-
-        self.assertEqual(response.status_code, 200)
-
 
 
 class SecretRoleTest(APITestCase):
 class SecretRoleTest(APITestCase):
 
 

+ 0 - 3
netbox/tenancy/api/urls.py

@@ -14,9 +14,6 @@ class TenancyRootView(routers.APIRootView):
 router = routers.DefaultRouter()
 router = routers.DefaultRouter()
 router.APIRootView = TenancyRootView
 router.APIRootView = TenancyRootView
 
 
-# Field choices
-router.register('_choices', views.TenancyFieldChoicesViewSet, basename='field-choice')
-
 # Tenants
 # Tenants
 router.register('tenant-groups', views.TenantGroupViewSet)
 router.register('tenant-groups', views.TenantGroupViewSet)
 router.register('tenants', views.TenantViewSet)
 router.register('tenants', views.TenantViewSet)

+ 1 - 9
netbox/tenancy/api/views.py

@@ -4,20 +4,12 @@ from extras.api.views import CustomFieldModelViewSet
 from ipam.models import IPAddress, Prefix, VLAN, VRF
 from ipam.models import IPAddress, Prefix, VLAN, VRF
 from tenancy import filters
 from tenancy import filters
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
-from utilities.api import FieldChoicesViewSet, ModelViewSet
+from utilities.api import ModelViewSet
 from utilities.utils import get_subquery
 from utilities.utils import get_subquery
 from virtualization.models import VirtualMachine
 from virtualization.models import VirtualMachine
 from . import serializers
 from . import serializers
 
 
 
 
-#
-# Field choices
-#
-
-class TenancyFieldChoicesViewSet(FieldChoicesViewSet):
-    fields = ()
-
-
 #
 #
 # Tenant Groups
 # Tenant Groups
 #
 #

+ 0 - 7
netbox/tenancy/tests/test_api.py

@@ -14,13 +14,6 @@ class AppTest(APITestCase):
 
 
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
-    def test_choices(self):
-
-        url = reverse('tenancy-api:field-choice-list')
-        response = self.client.get(url, **self.header)
-
-        self.assertEqual(response.status_code, 200)
-
 
 
 class TenantGroupTest(APITestCase):
 class TenantGroupTest(APITestCase):
 
 

+ 0 - 46
netbox/utilities/api.py

@@ -371,49 +371,3 @@ class ModelViewSet(_ModelViewSet):
         logger = logging.getLogger('netbox.api.views.ModelViewSet')
         logger = logging.getLogger('netbox.api.views.ModelViewSet')
         logger.info(f"Deleting {instance} (PK: {instance.pk})")
         logger.info(f"Deleting {instance} (PK: {instance.pk})")
         return super().perform_destroy(instance)
         return super().perform_destroy(instance)
-
-
-class FieldChoicesViewSet(ViewSet):
-    """
-    Expose the built-in numeric values which represent static choices for a model's field.
-    """
-    permission_classes = [IsAuthenticatedOrLoginNotRequired]
-    fields = []
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-
-        # Compile a dict of all fields in this view
-        self._fields = OrderedDict()
-        for serializer_class, field_list in self.fields:
-            for field_name in field_list:
-
-                model_name = serializer_class.Meta.model._meta.verbose_name
-                key = ':'.join([model_name.lower().replace(' ', '-'), field_name])
-                serializer = serializer_class()
-                choices = []
-
-                for k, v in serializer.get_fields()[field_name].choices.items():
-                    if type(v) in [list, tuple]:
-                        for k2, v2 in v:
-                            choices.append({
-                                'value': k2,
-                                'label': v2,
-                            })
-                    else:
-                        choices.append({
-                            'value': k,
-                            'label': v,
-                        })
-                self._fields[key] = choices
-
-    def list(self, request):
-        return Response(self._fields)
-
-    def retrieve(self, request, pk):
-        if pk not in self._fields:
-            raise Http404
-        return Response(self._fields[pk])
-
-    def get_view_name(self):
-        return "Field Choices"

+ 0 - 27
netbox/utilities/testing/utils.py

@@ -36,33 +36,6 @@ def create_test_user(username='testuser', permissions=None):
     return user
     return user
 
 
 
 
-def choices_to_dict(choices_list):
-    """
-    Convert a list of field choices to a dictionary suitable for direct comparison with a ChoiceSet. For example:
-
-        [
-            {
-                "value": "choice-1",
-                "label": "First Choice"
-            },
-            {
-                "value": "choice-2",
-                "label": "Second Choice"
-            }
-        ]
-
-    Becomes:
-
-        {
-            "choice-1": "First Choice",
-            "choice-2": "Second Choice
-        }
-    """
-    return {
-        choice['value']: choice['label'] for choice in choices_list
-    }
-
-
 @contextmanager
 @contextmanager
 def disable_warnings(logger_name):
 def disable_warnings(logger_name):
     """
     """

+ 0 - 3
netbox/virtualization/api/urls.py

@@ -14,9 +14,6 @@ class VirtualizationRootView(routers.APIRootView):
 router = routers.DefaultRouter()
 router = routers.DefaultRouter()
 router.APIRootView = VirtualizationRootView
 router.APIRootView = VirtualizationRootView
 
 
-# Field choices
-router.register('_choices', views.VirtualizationFieldChoicesViewSet, basename='field-choice')
-
 # Clusters
 # Clusters
 router.register('cluster-types', views.ClusterTypeViewSet)
 router.register('cluster-types', views.ClusterTypeViewSet)
 router.register('cluster-groups', views.ClusterGroupViewSet)
 router.register('cluster-groups', views.ClusterGroupViewSet)

+ 1 - 12
netbox/virtualization/api/views.py

@@ -2,24 +2,13 @@ from django.db.models import Count
 
 
 from dcim.models import Device, Interface
 from dcim.models import Device, Interface
 from extras.api.views import CustomFieldModelViewSet
 from extras.api.views import CustomFieldModelViewSet
-from utilities.api import FieldChoicesViewSet, ModelViewSet
+from utilities.api import ModelViewSet
 from utilities.utils import get_subquery
 from utilities.utils import get_subquery
 from virtualization import filters
 from virtualization import filters
 from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 from . import serializers
 from . import serializers
 
 
 
 
-#
-# Field choices
-#
-
-class VirtualizationFieldChoicesViewSet(FieldChoicesViewSet):
-    fields = (
-        (serializers.VirtualMachineSerializer, ['status']),
-        (serializers.InterfaceSerializer, ['type']),
-    )
-
-
 #
 #
 # Clusters
 # Clusters
 #
 #

+ 1 - 14
netbox/virtualization/tests/test_api.py

@@ -5,7 +5,7 @@ from rest_framework import status
 from dcim.choices import InterfaceModeChoices
 from dcim.choices import InterfaceModeChoices
 from dcim.models import Interface
 from dcim.models import Interface
 from ipam.models import IPAddress, VLAN
 from ipam.models import IPAddress, VLAN
-from utilities.testing import APITestCase, choices_to_dict, disable_warnings
+from utilities.testing import APITestCase, disable_warnings
 from virtualization.choices import *
 from virtualization.choices import *
 from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 
 
@@ -19,19 +19,6 @@ class AppTest(APITestCase):
 
 
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
-    def test_choices(self):
-
-        url = reverse('virtualization-api:field-choice-list')
-        response = self.client.get(url, **self.header)
-
-        self.assertEqual(response.status_code, 200)
-
-        # VirtualMachine
-        self.assertEqual(choices_to_dict(response.data.get('virtual-machine:status')), VirtualMachineStatusChoices.as_dict())
-
-        # Interface
-        self.assertEqual(choices_to_dict(response.data.get('interface:type')), VMInterfaceTypeChoices.as_dict())
-
 
 
 class ClusterTypeTest(APITestCase):
 class ClusterTypeTest(APITestCase):