mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Closes #4997: Introduce OrderedDefaultRouter; move root API views to views.py
This commit is contained in:
@ -14,6 +14,7 @@
|
|||||||
* [#4982](https://github.com/netbox-community/netbox/issues/4982) - Extended ObjectVar to allow filtering API query
|
* [#4982](https://github.com/netbox-community/netbox/issues/4982) - Extended ObjectVar to allow filtering API query
|
||||||
* [#4994](https://github.com/netbox-community/netbox/issues/4994) - Add `cable` attribute to PowerFeed API serializer
|
* [#4994](https://github.com/netbox-community/netbox/issues/4994) - Add `cable` attribute to PowerFeed API serializer
|
||||||
* [#4996](https://github.com/netbox-community/netbox/issues/4996) - Add "connect" buttons to individual device component views
|
* [#4996](https://github.com/netbox-community/netbox/issues/4996) - Add "connect" buttons to individual device component views
|
||||||
|
* [#4997](https://github.com/netbox-community/netbox/issues/4997) - The browsable API now lists available endpoints alphabetically
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
from rest_framework import routers
|
from utilities.api import OrderedDefaultRouter
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
class CircuitsRootView(routers.APIRootView):
|
router = OrderedDefaultRouter()
|
||||||
"""
|
router.APIRootView = views.CircuitsRootView
|
||||||
Circuits API root view
|
|
||||||
"""
|
|
||||||
def get_view_name(self):
|
|
||||||
return 'Circuits'
|
|
||||||
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
|
||||||
router.APIRootView = CircuitsRootView
|
|
||||||
|
|
||||||
# Providers
|
# Providers
|
||||||
router.register('providers', views.ProviderViewSet)
|
router.register('providers', views.ProviderViewSet)
|
||||||
|
@ -2,6 +2,7 @@ from django.db.models import Count, Prefetch
|
|||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.routers import APIRootView
|
||||||
|
|
||||||
from circuits import filters
|
from circuits import filters
|
||||||
from circuits.models import Provider, CircuitTermination, CircuitType, Circuit
|
from circuits.models import Provider, CircuitTermination, CircuitType, Circuit
|
||||||
@ -12,6 +13,14 @@ from utilities.api import ModelViewSet
|
|||||||
from . import serializers
|
from . import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class CircuitsRootView(APIRootView):
|
||||||
|
"""
|
||||||
|
Circuits API root view
|
||||||
|
"""
|
||||||
|
def get_view_name(self):
|
||||||
|
return 'Circuits'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Providers
|
# Providers
|
||||||
#
|
#
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
from rest_framework import routers
|
from utilities.api import OrderedDefaultRouter
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
class DCIMRootView(routers.APIRootView):
|
router = OrderedDefaultRouter()
|
||||||
"""
|
router.APIRootView = views.DCIMRootView
|
||||||
DCIM API root view
|
|
||||||
"""
|
|
||||||
def get_view_name(self):
|
|
||||||
return 'DCIM'
|
|
||||||
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
|
||||||
router.APIRootView = DCIMRootView
|
|
||||||
|
|
||||||
# Sites
|
# Sites
|
||||||
router.register('regions', views.RegionViewSet)
|
router.register('regions', views.RegionViewSet)
|
||||||
|
@ -11,6 +11,7 @@ from drf_yasg.utils import swagger_auto_schema
|
|||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.mixins import ListModelMixin
|
from rest_framework.mixins import ListModelMixin
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.routers import APIRootView
|
||||||
from rest_framework.viewsets import GenericViewSet, ViewSet
|
from rest_framework.viewsets import GenericViewSet, ViewSet
|
||||||
|
|
||||||
from circuits.models import Circuit
|
from circuits.models import Circuit
|
||||||
@ -36,6 +37,14 @@ from . import serializers
|
|||||||
from .exceptions import MissingFilterException
|
from .exceptions import MissingFilterException
|
||||||
|
|
||||||
|
|
||||||
|
class DCIMRootView(APIRootView):
|
||||||
|
"""
|
||||||
|
DCIM API root view
|
||||||
|
"""
|
||||||
|
def get_view_name(self):
|
||||||
|
return 'DCIM'
|
||||||
|
|
||||||
|
|
||||||
# Mixins
|
# Mixins
|
||||||
|
|
||||||
class CableTraceMixin(object):
|
class CableTraceMixin(object):
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
from rest_framework import routers
|
from utilities.api import OrderedDefaultRouter
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
class ExtrasRootView(routers.APIRootView):
|
router = OrderedDefaultRouter()
|
||||||
"""
|
router.APIRootView = views.ExtrasRootView
|
||||||
Extras API root view
|
|
||||||
"""
|
|
||||||
def get_view_name(self):
|
|
||||||
return 'Extras'
|
|
||||||
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
|
||||||
router.APIRootView = ExtrasRootView
|
|
||||||
|
|
||||||
# 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')
|
||||||
|
@ -8,6 +8,7 @@ from rest_framework import status
|
|||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.routers import APIRootView
|
||||||
from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet
|
from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet
|
||||||
from rq import Worker
|
from rq import Worker
|
||||||
|
|
||||||
@ -25,6 +26,14 @@ from utilities.utils import copy_safe_request
|
|||||||
from . import serializers
|
from . import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class ExtrasRootView(APIRootView):
|
||||||
|
"""
|
||||||
|
Extras API root view
|
||||||
|
"""
|
||||||
|
def get_view_name(self):
|
||||||
|
return 'Extras'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Custom field choices
|
# Custom field choices
|
||||||
#
|
#
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
from rest_framework import routers
|
from utilities.api import OrderedDefaultRouter
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
class IPAMRootView(routers.APIRootView):
|
router = OrderedDefaultRouter()
|
||||||
"""
|
router.APIRootView = views.IPAMRootView
|
||||||
IPAM API root view
|
|
||||||
"""
|
|
||||||
def get_view_name(self):
|
|
||||||
return 'IPAM'
|
|
||||||
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
|
||||||
router.APIRootView = IPAMRootView
|
|
||||||
|
|
||||||
# VRFs
|
# VRFs
|
||||||
router.register('vrfs', views.VRFViewSet)
|
router.register('vrfs', views.VRFViewSet)
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import Count, Prefetch
|
from django.db.models import Count
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django_pglocks import advisory_lock
|
from django_pglocks import advisory_lock
|
||||||
from drf_yasg.utils import swagger_auto_schema
|
from drf_yasg.utils import swagger_auto_schema
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.routers import APIRootView
|
||||||
|
|
||||||
from extras.api.views import CustomFieldModelViewSet
|
from extras.api.views import CustomFieldModelViewSet
|
||||||
from ipam import filters
|
from ipam import filters
|
||||||
@ -16,6 +17,14 @@ from utilities.utils import get_subquery
|
|||||||
from . import serializers
|
from . import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class IPAMRootView(APIRootView):
|
||||||
|
"""
|
||||||
|
IPAM API root view
|
||||||
|
"""
|
||||||
|
def get_view_name(self):
|
||||||
|
return 'IPAM'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# VRFs
|
# VRFs
|
||||||
#
|
#
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
from rest_framework import routers
|
from utilities.api import OrderedDefaultRouter
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
class SecretsRootView(routers.APIRootView):
|
router = OrderedDefaultRouter()
|
||||||
"""
|
router.APIRootView = views.SecretsRootView
|
||||||
Secrets API root view
|
|
||||||
"""
|
|
||||||
def get_view_name(self):
|
|
||||||
return 'Secrets'
|
|
||||||
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
|
||||||
router.APIRootView = SecretsRootView
|
|
||||||
|
|
||||||
# Secrets
|
# Secrets
|
||||||
router.register('secret-roles', views.SecretRoleViewSet)
|
router.register('secret-roles', views.SecretRoleViewSet)
|
||||||
|
@ -6,6 +6,7 @@ from django.http import HttpResponseBadRequest
|
|||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.routers import APIRootView
|
||||||
from rest_framework.viewsets import ViewSet
|
from rest_framework.viewsets import ViewSet
|
||||||
|
|
||||||
from secrets import filters
|
from secrets import filters
|
||||||
@ -20,6 +21,14 @@ ERR_PRIVKEY_MISSING = "Private key was not provided."
|
|||||||
ERR_PRIVKEY_INVALID = "Invalid private key."
|
ERR_PRIVKEY_INVALID = "Invalid private key."
|
||||||
|
|
||||||
|
|
||||||
|
class SecretsRootView(APIRootView):
|
||||||
|
"""
|
||||||
|
Secrets API root view
|
||||||
|
"""
|
||||||
|
def get_view_name(self):
|
||||||
|
return 'Secrets'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Secret Roles
|
# Secret Roles
|
||||||
#
|
#
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
from rest_framework import routers
|
from utilities.api import OrderedDefaultRouter
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
class TenancyRootView(routers.APIRootView):
|
router = OrderedDefaultRouter()
|
||||||
"""
|
router.APIRootView = views.TenancyRootView
|
||||||
Tenancy API root view
|
|
||||||
"""
|
|
||||||
def get_view_name(self):
|
|
||||||
return 'Tenancy'
|
|
||||||
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
|
||||||
router.APIRootView = TenancyRootView
|
|
||||||
|
|
||||||
# Tenants
|
# Tenants
|
||||||
router.register('tenant-groups', views.TenantGroupViewSet)
|
router.register('tenant-groups', views.TenantGroupViewSet)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from rest_framework.routers import APIRootView
|
||||||
|
|
||||||
from circuits.models import Circuit
|
from circuits.models import Circuit
|
||||||
from dcim.models import Device, Rack, Site
|
from dcim.models import Device, Rack, Site
|
||||||
from extras.api.views import CustomFieldModelViewSet
|
from extras.api.views import CustomFieldModelViewSet
|
||||||
@ -10,6 +12,14 @@ from virtualization.models import VirtualMachine
|
|||||||
from . import serializers
|
from . import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class TenancyRootView(APIRootView):
|
||||||
|
"""
|
||||||
|
Tenancy API root view
|
||||||
|
"""
|
||||||
|
def get_view_name(self):
|
||||||
|
return 'Tenancy'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Tenant Groups
|
# Tenant Groups
|
||||||
#
|
#
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
from rest_framework import routers
|
from utilities.api import OrderedDefaultRouter
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
class UsersRootView(routers.APIRootView):
|
router = OrderedDefaultRouter()
|
||||||
"""
|
router.APIRootView = views.UsersRootView
|
||||||
Users API root view
|
|
||||||
"""
|
|
||||||
def get_view_name(self):
|
|
||||||
return 'Users'
|
|
||||||
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
|
||||||
router.APIRootView = UsersRootView
|
|
||||||
|
|
||||||
# Users and groups
|
# Users and groups
|
||||||
router.register('users', views.UserViewSet)
|
router.register('users', views.UserViewSet)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
|
from rest_framework.routers import APIRootView
|
||||||
|
|
||||||
from users import filters
|
from users import filters
|
||||||
from users.models import ObjectPermission
|
from users.models import ObjectPermission
|
||||||
@ -8,6 +9,14 @@ from utilities.querysets import RestrictedQuerySet
|
|||||||
from . import serializers
|
from . import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class UsersRootView(APIRootView):
|
||||||
|
"""
|
||||||
|
Users API root view
|
||||||
|
"""
|
||||||
|
def get_view_name(self):
|
||||||
|
return 'Users'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Users and groups
|
# Users and groups
|
||||||
#
|
#
|
||||||
|
@ -13,6 +13,7 @@ from rest_framework.exceptions import APIException, ValidationError
|
|||||||
from rest_framework.permissions import BasePermission
|
from rest_framework.permissions import BasePermission
|
||||||
from rest_framework.relations import PrimaryKeyRelatedField, RelatedField
|
from rest_framework.relations import PrimaryKeyRelatedField, RelatedField
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.routers import DefaultRouter
|
||||||
from rest_framework.viewsets import ModelViewSet as _ModelViewSet
|
from rest_framework.viewsets import ModelViewSet as _ModelViewSet
|
||||||
|
|
||||||
from .utils import dict_to_filter_params, dynamic_import
|
from .utils import dict_to_filter_params, dynamic_import
|
||||||
@ -399,3 +400,21 @@ class ModelViewSet(_ModelViewSet):
|
|||||||
logger.info(f"Deleting {model._meta.verbose_name} {instance} (PK: {instance.pk})")
|
logger.info(f"Deleting {model._meta.verbose_name} {instance} (PK: {instance.pk})")
|
||||||
|
|
||||||
return super().perform_destroy(instance)
|
return super().perform_destroy(instance)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Routers
|
||||||
|
#
|
||||||
|
|
||||||
|
class OrderedDefaultRouter(DefaultRouter):
|
||||||
|
|
||||||
|
def get_api_root_view(self, api_urls=None):
|
||||||
|
"""
|
||||||
|
Wrap DRF's DefaultRouter to return an alphabetized list of endpoints.
|
||||||
|
"""
|
||||||
|
api_root_dict = OrderedDict()
|
||||||
|
list_name = self.routes[0].name
|
||||||
|
for prefix, viewset, basename in sorted(self.registry, key=lambda x: x[0]):
|
||||||
|
api_root_dict[prefix] = list_name.format(basename=basename)
|
||||||
|
|
||||||
|
return self.APIRootView.as_view(api_root_dict=api_root_dict)
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
from rest_framework import routers
|
from utilities.api import OrderedDefaultRouter
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
class VirtualizationRootView(routers.APIRootView):
|
router = OrderedDefaultRouter()
|
||||||
"""
|
router.APIRootView = views.VirtualizationRootView
|
||||||
Virtualization API root view
|
|
||||||
"""
|
|
||||||
def get_view_name(self):
|
|
||||||
return 'Virtualization'
|
|
||||||
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
|
||||||
router.APIRootView = VirtualizationRootView
|
|
||||||
|
|
||||||
# Clusters
|
# Clusters
|
||||||
router.register('cluster-types', views.ClusterTypeViewSet)
|
router.register('cluster-types', views.ClusterTypeViewSet)
|
||||||
|
@ -2,6 +2,7 @@ from django.db.models import Count
|
|||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.routers import APIRootView
|
||||||
|
|
||||||
from dcim.models import Device
|
from dcim.models import Device
|
||||||
from extras.api.serializers import RenderedGraphSerializer
|
from extras.api.serializers import RenderedGraphSerializer
|
||||||
@ -14,6 +15,14 @@ from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMac
|
|||||||
from . import serializers
|
from . import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualizationRootView(APIRootView):
|
||||||
|
"""
|
||||||
|
Virtualization API root view
|
||||||
|
"""
|
||||||
|
def get_view_name(self):
|
||||||
|
return 'Virtualization'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Clusters
|
# Clusters
|
||||||
#
|
#
|
||||||
|
Reference in New Issue
Block a user