From 4971469590abbcc69490d4399597a4eb9a602fcb Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 10 Nov 2020 17:13:22 -0500 Subject: [PATCH] Move APIRootView to netbox.api.views --- netbox/netbox/api/views.py | 29 +++++++++++++++++++++++++++++ netbox/netbox/urls.py | 4 ++-- netbox/netbox/views.py | 30 ++---------------------------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/netbox/netbox/api/views.py b/netbox/netbox/api/views.py index 309cbb4aa..f63b3134f 100644 --- a/netbox/netbox/api/views.py +++ b/netbox/netbox/api/views.py @@ -1,5 +1,6 @@ import logging import platform +from collections import OrderedDict from django import __version__ as DJANGO_VERSION from django.apps import apps @@ -10,6 +11,7 @@ from django.db.models import ProtectedError from django_rq.queues import get_connection from rest_framework import mixins, status from rest_framework.response import Response +from rest_framework.reverse import reverse from rest_framework.views import APIView from rest_framework.viewsets import GenericViewSet from rq.worker import Worker @@ -232,6 +234,33 @@ class ModelViewSet(mixins.CreateModelMixin, # Views # +class APIRootView(APIView): + """ + This is the root of NetBox's REST API. API endpoints are arranged by app and model name; e.g. `/api/dcim/sites/`. + """ + _ignore_model_permissions = True + exclude_from_schema = True + swagger_schema = None + + def get_view_name(self): + return "API Root" + + def get(self, request, format=None): + + return Response(OrderedDict(( + ('circuits', reverse('circuits-api:api-root', request=request, format=format)), + ('dcim', reverse('dcim-api:api-root', request=request, format=format)), + ('extras', reverse('extras-api:api-root', request=request, format=format)), + ('ipam', reverse('ipam-api:api-root', request=request, format=format)), + ('plugins', reverse('plugins-api:api-root', request=request, format=format)), + ('secrets', reverse('secrets-api:api-root', request=request, format=format)), + ('status', reverse('api-status', request=request, format=format)), + ('tenancy', reverse('tenancy-api:api-root', request=request, format=format)), + ('users', reverse('users-api:api-root', request=request, format=format)), + ('virtualization', reverse('virtualization-api:api-root', request=request, format=format)), + ))) + + class StatusView(APIView): """ A lightweight read-only endpoint for conveying NetBox's current operational status. diff --git a/netbox/netbox/urls.py b/netbox/netbox/urls.py index 250b1ac67..dc24cc9eb 100644 --- a/netbox/netbox/urls.py +++ b/netbox/netbox/urls.py @@ -6,8 +6,8 @@ from drf_yasg import openapi from drf_yasg.views import get_schema_view from extras.plugins.urls import plugin_admin_patterns, plugin_patterns, plugin_api_patterns -from netbox.api.views import StatusView -from netbox.views import APIRootView, HomeView, StaticMediaFailureView, SearchView +from netbox.api.views import APIRootView, StatusView +from netbox.views import HomeView, StaticMediaFailureView, SearchView from users.views import LoginView, LogoutView from .admin import admin_site diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index baf014dbf..4d0def683 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -4,11 +4,9 @@ from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.db.models import Count, F from django.shortcuts import render +from django.urls import reverse from django.views.generic import View from packaging import version -from rest_framework.response import Response -from rest_framework.reverse import reverse -from rest_framework.views import APIView from circuits.filters import CircuitFilterSet, ProviderFilterSet from circuits.models import Circuit, Provider @@ -306,7 +304,7 @@ class SearchView(View): results.append({ 'name': queryset.model._meta.verbose_name_plural, 'table': table, - 'url': '{}?q={}'.format(reverse(url), form.cleaned_data['q']) + 'url': f"{reverse(url)}?q={form.cleaned_data.get('q')}" }) return render(request, 'search.html', { @@ -323,27 +321,3 @@ class StaticMediaFailureView(View): return render(request, 'media_failure.html', { 'filename': request.GET.get('filename') }) - - -class APIRootView(APIView): - _ignore_model_permissions = True - exclude_from_schema = True - swagger_schema = None - - def get_view_name(self): - return "API Root" - - def get(self, request, format=None): - - return Response(OrderedDict(( - ('circuits', reverse('circuits-api:api-root', request=request, format=format)), - ('dcim', reverse('dcim-api:api-root', request=request, format=format)), - ('extras', reverse('extras-api:api-root', request=request, format=format)), - ('ipam', reverse('ipam-api:api-root', request=request, format=format)), - ('plugins', reverse('plugins-api:api-root', request=request, format=format)), - ('secrets', reverse('secrets-api:api-root', request=request, format=format)), - ('status', reverse('api-status', request=request, format=format)), - ('tenancy', reverse('tenancy-api:api-root', request=request, format=format)), - ('users', reverse('users-api:api-root', request=request, format=format)), - ('virtualization', reverse('virtualization-api:api-root', request=request, format=format)), - )))