Initial work on API v2.0

This commit is contained in:
Jeremy Stretch 2017-01-24 17:12:16 -05:00
parent 960d4d5b5e
commit 4d72ee291b
14 changed files with 216 additions and 386 deletions

View File

@ -9,17 +9,17 @@ from .views import *
urlpatterns = [ urlpatterns = [
# Providers # Providers
url(r'^providers/$', ProviderListView.as_view(), name='provider_list'), url(r'^providers/$', ProviderViewSet.as_view({'get': 'list'}), name='provider_list'),
url(r'^providers/(?P<pk>\d+)/$', ProviderDetailView.as_view(), name='provider_detail'), url(r'^providers/(?P<pk>\d+)/$', ProviderViewSet.as_view({'get': 'retrieve'}), name='provider_detail'),
url(r'^providers/(?P<pk>\d+)/graphs/$', GraphListView.as_view(), {'type': GRAPH_TYPE_PROVIDER}, url(r'^providers/(?P<pk>\d+)/graphs/$', GraphListView.as_view(), {'type': GRAPH_TYPE_PROVIDER},
name='provider_graphs'), name='provider_graphs'),
# Circuit types # Circuit types
url(r'^circuit-types/$', CircuitTypeListView.as_view(), name='circuittype_list'), url(r'^circuit-types/$', CircuitTypeViewSet.as_view({'get': 'list'}), name='circuittype_list'),
url(r'^circuit-types/(?P<pk>\d+)/$', CircuitTypeDetailView.as_view(), name='circuittype_detail'), url(r'^circuit-types/(?P<pk>\d+)/$', CircuitTypeViewSet.as_view({'get': 'retrieve'}), name='circuittype_detail'),
# Circuits # Circuits
url(r'^circuits/$', CircuitListView.as_view(), name='circuit_list'), url(r'^circuits/$', CircuitViewSet.as_view({'get': 'list'}), name='circuit_list'),
url(r'^circuits/(?P<pk>\d+)/$', CircuitDetailView.as_view(), name='circuit_detail'), url(r'^circuits/(?P<pk>\d+)/$', CircuitViewSet.as_view({'get': 'retrieve'}), name='circuit_detail'),
] ]

View File

@ -1,58 +1,44 @@
from rest_framework import generics from rest_framework.viewsets import ModelViewSet
from circuits.models import Provider, CircuitType, Circuit from circuits.models import Provider, CircuitType, Circuit
from circuits.filters import CircuitFilter from circuits.filters import CircuitFilter
from extras.api.views import CustomFieldModelAPIView from extras.api.views import CustomFieldModelViewSet
from . import serializers from . import serializers
class ProviderListView(CustomFieldModelAPIView, generics.ListAPIView): #
# Providers
#
class ProviderViewSet(CustomFieldModelViewSet):
""" """
List all providers List and retrieve circuit providers
""" """
queryset = Provider.objects.prefetch_related('custom_field_values__field') queryset = Provider.objects.all()
serializer_class = serializers.ProviderSerializer serializer_class = serializers.ProviderSerializer
class ProviderDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView): #
""" # Circuit Types
Retrieve a single provider #
"""
queryset = Provider.objects.prefetch_related('custom_field_values__field')
serializer_class = serializers.ProviderSerializer
class CircuitTypeViewSet(ModelViewSet):
class CircuitTypeListView(generics.ListAPIView):
""" """
List all circuit types List and retrieve circuit types
""" """
queryset = CircuitType.objects.all() queryset = CircuitType.objects.all()
serializer_class = serializers.CircuitTypeSerializer serializer_class = serializers.CircuitTypeSerializer
class CircuitTypeDetailView(generics.RetrieveAPIView): #
""" # Circuits
Retrieve a single circuit type #
"""
queryset = CircuitType.objects.all()
serializer_class = serializers.CircuitTypeSerializer
class CircuitViewSet(CustomFieldModelViewSet):
class CircuitListView(CustomFieldModelAPIView, generics.ListAPIView):
""" """
List circuits (filterable) List and retrieve circuits
""" """
queryset = Circuit.objects.select_related('type', 'tenant', 'provider')\ queryset = Circuit.objects.select_related('type', 'tenant', 'provider')
.prefetch_related('custom_field_values__field')
serializer_class = serializers.CircuitSerializer serializer_class = serializers.CircuitSerializer
filter_class = CircuitFilter filter_class = CircuitFilter
class CircuitDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
"""
Retrieve a single circuit
"""
queryset = Circuit.objects.select_related('type', 'tenant', 'provider')\
.prefetch_related('custom_field_values__field')
serializer_class = serializers.CircuitSerializer

View File

@ -9,52 +9,50 @@ from .views import *
urlpatterns = [ urlpatterns = [
# Sites # Sites
url(r'^sites/$', SiteListView.as_view(), name='site_list'), url(r'^sites/$', SiteViewSet.as_view({'get': 'list'}), name='site_list'),
url(r'^sites/(?P<pk>\d+)/$', SiteDetailView.as_view(), name='site_detail'), url(r'^sites/(?P<pk>\d+)/$', SiteViewSet.as_view({'get': 'retrieve'}), name='site_detail'),
url(r'^sites/(?P<pk>\d+)/graphs/$', GraphListView.as_view(), {'type': GRAPH_TYPE_SITE}, name='site_graphs'), url(r'^sites/(?P<pk>\d+)/graphs/$', GraphListView.as_view(), {'type': GRAPH_TYPE_SITE}, name='site_graphs'),
url(r'^sites/(?P<site>\d+)/racks/$', RackListView.as_view(), name='site_racks'),
# Rack groups # Rack groups
url(r'^rack-groups/$', RackGroupListView.as_view(), name='rackgroup_list'), url(r'^rack-groups/$', RackGroupViewSet.as_view({'get': 'list'}), name='rackgroup_list'),
url(r'^rack-groups/(?P<pk>\d+)/$', RackGroupDetailView.as_view(), name='rackgroup_detail'), url(r'^rack-groups/(?P<pk>\d+)/$', RackGroupViewSet.as_view({'get': 'retrieve'}), name='rackgroup_detail'),
# Rack roles # Rack roles
url(r'^rack-roles/$', RackRoleListView.as_view(), name='rackrole_list'), url(r'^rack-roles/$', RackRoleViewSet.as_view({'get': 'list'}), name='rackrole_list'),
url(r'^rack-roles/(?P<pk>\d+)/$', RackRoleDetailView.as_view(), name='rackrole_detail'), url(r'^rack-roles/(?P<pk>\d+)/$', RackRoleViewSet.as_view({'get': 'retrieve'}), name='rackrole_detail'),
# Racks # Racks
url(r'^racks/$', RackListView.as_view(), name='rack_list'), url(r'^racks/$', RackViewSet.as_view({'get': 'list'}), name='rack_list'),
url(r'^racks/(?P<pk>\d+)/$', RackDetailView.as_view(), name='rack_detail'), url(r'^racks/(?P<pk>\d+)/$', RackViewSet.as_view({'get': 'retrieve'}), name='rack_detail'),
url(r'^racks/(?P<pk>\d+)/rack-units/$', RackUnitListView.as_view(), name='rack_units'), url(r'^racks/(?P<pk>\d+)/rack-units/$', RackUnitListView.as_view(), name='rack_units'),
# Manufacturers # Manufacturers
url(r'^manufacturers/$', ManufacturerListView.as_view(), name='manufacturer_list'), url(r'^manufacturers/$', ManufacturerViewSet.as_view({'get': 'list'}), name='manufacturer_list'),
url(r'^manufacturers/(?P<pk>\d+)/$', ManufacturerDetailView.as_view(), name='manufacturer_detail'), url(r'^manufacturers/(?P<pk>\d+)/$', ManufacturerViewSet.as_view({'get': 'retrieve'}), name='manufacturer_detail'),
# Device types # Device types
url(r'^device-types/$', DeviceTypeListView.as_view(), name='devicetype_list'), url(r'^device-types/$', DeviceTypeViewSet.as_view({'get': 'list'}), name='devicetype_list'),
url(r'^device-types/(?P<pk>\d+)/$', DeviceTypeDetailView.as_view(), name='devicetype_detail'), url(r'^device-types/(?P<pk>\d+)/$', DeviceTypeViewSet.as_view({'get': 'retrieve'}), name='devicetype_detail'),
# Device roles # Device roles
url(r'^device-roles/$', DeviceRoleListView.as_view(), name='devicerole_list'), url(r'^device-roles/$', DeviceRoleViewSet.as_view({'get': 'list'}), name='devicerole_list'),
url(r'^device-roles/(?P<pk>\d+)/$', DeviceRoleDetailView.as_view(), name='devicerole_detail'), url(r'^device-roles/(?P<pk>\d+)/$', DeviceRoleViewSet.as_view({'get': 'retrieve'}), name='devicerole_detail'),
# Platforms # Platforms
url(r'^platforms/$', PlatformListView.as_view(), name='platform_list'), url(r'^platforms/$', PlatformViewSet.as_view({'get': 'list'}), name='platform_list'),
url(r'^platforms/(?P<pk>\d+)/$', PlatformDetailView.as_view(), name='platform_detail'), url(r'^platforms/(?P<pk>\d+)/$', PlatformViewSet.as_view({'get': 'retrieve'}), name='platform_detail'),
# Devices # Devices
url(r'^devices/$', DeviceListView.as_view(), name='device_list'), url(r'^devices/$', DeviceViewSet.as_view({'get': 'list'}), name='device_list'),
url(r'^devices/(?P<pk>\d+)/$', DeviceDetailView.as_view(), name='device_detail'), url(r'^devices/(?P<pk>\d+)/$', DeviceViewSet.as_view({'get': 'retrieve'}), name='device_detail'),
url(r'^devices/(?P<pk>\d+)/lldp-neighbors/$', LLDPNeighborsView.as_view(), name='device_lldp-neighbors'), url(r'^devices/(?P<pk>\d+)/lldp-neighbors/$', LLDPNeighborsView.as_view(), name='device_lldp-neighbors'),
url(r'^devices/(?P<pk>\d+)/console-ports/$', ConsolePortListView.as_view(), name='device_consoleports'), url(r'^devices/(?P<pk>\d+)/console-ports/$', ConsolePortViewSet.as_view({'get': 'list'}), name='device_consoleports'),
url(r'^devices/(?P<pk>\d+)/console-server-ports/$', ConsoleServerPortListView.as_view(), url(r'^devices/(?P<pk>\d+)/console-server-ports/$', ConsoleServerPortViewSet.as_view({'get': 'list'}), name='device_consoleserverports'),
name='device_consoleserverports'), url(r'^devices/(?P<pk>\d+)/power-ports/$', PowerPortViewSet.as_view({'get': 'list'}), name='device_powerports'),
url(r'^devices/(?P<pk>\d+)/power-ports/$', PowerPortListView.as_view(), name='device_powerports'), url(r'^devices/(?P<pk>\d+)/power-outlets/$', PowerOutletViewSet.as_view({'get': 'list'}), name='device_poweroutlets'),
url(r'^devices/(?P<pk>\d+)/power-outlets/$', PowerOutletListView.as_view(), name='device_poweroutlets'), url(r'^devices/(?P<pk>\d+)/interfaces/$', InterfaceViewSet.as_view({'get': 'list'}), name='device_interfaces'),
url(r'^devices/(?P<pk>\d+)/interfaces/$', InterfaceListView.as_view(), name='device_interfaces'), url(r'^devices/(?P<pk>\d+)/device-bays/$', DeviceBayViewSet.as_view({'get': 'list'}), name='device_devicebays'),
url(r'^devices/(?P<pk>\d+)/device-bays/$', DeviceBayListView.as_view(), name='device_devicebays'), url(r'^devices/(?P<pk>\d+)/modules/$', ModuleViewSet.as_view({'get': 'list'}), name='device_modules'),
url(r'^devices/(?P<pk>\d+)/modules/$', ModuleListView.as_view(), name='device_modules'),
# Console ports # Console ports
url(r'^console-ports/(?P<pk>\d+)/$', ConsolePortView.as_view(), name='consoleport'), url(r'^console-ports/(?P<pk>\d+)/$', ConsolePortView.as_view(), name='consoleport'),

View File

@ -3,10 +3,10 @@ from rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.settings import api_settings from rest_framework.settings import api_settings
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db.models import Count
from django.http import Http404 from django.http import Http404
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
@ -15,7 +15,7 @@ from dcim.models import (
InterfaceConnection, Manufacturer, Module, Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, Site, InterfaceConnection, Manufacturer, Module, Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, Site,
) )
from dcim import filters from dcim import filters
from extras.api.views import CustomFieldModelAPIView from extras.api.views import CustomFieldModelViewSet
from extras.api.renderers import BINDZoneRenderer, FlatJSONRenderer from extras.api.renderers import BINDZoneRenderer, FlatJSONRenderer
from utilities.api import ServiceUnavailable from utilities.api import ServiceUnavailable
from .exceptions import MissingFilterException from .exceptions import MissingFilterException
@ -26,19 +26,11 @@ from . import serializers
# Sites # Sites
# #
class SiteListView(CustomFieldModelAPIView, generics.ListAPIView): class SiteViewSet(CustomFieldModelViewSet):
""" """
List all sites List and retrieve sites
""" """
queryset = Site.objects.select_related('tenant').prefetch_related('custom_field_values__field') queryset = Site.objects.select_related('tenant')
serializer_class = serializers.SiteSerializer
class SiteDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
"""
Retrieve a single site
"""
queryset = Site.objects.select_related('tenant').prefetch_related('custom_field_values__field')
serializer_class = serializers.SiteSerializer serializer_class = serializers.SiteSerializer
@ -46,38 +38,22 @@ class SiteDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
# Rack groups # Rack groups
# #
class RackGroupListView(generics.ListAPIView): class RackGroupViewSet(ModelViewSet):
""" """
List all rack groups List and retrieve rack groups
""" """
queryset = RackGroup.objects.select_related('site') queryset = RackGroup.objects.select_related('site')
serializer_class = serializers.RackGroupSerializer serializer_class = serializers.RackGroupSerializer
filter_class = filters.RackGroupFilter filter_class = filters.RackGroupFilter
class RackGroupDetailView(generics.RetrieveAPIView):
"""
Retrieve a single rack group
"""
queryset = RackGroup.objects.select_related('site')
serializer_class = serializers.RackGroupSerializer
# #
# Rack roles # Rack roles
# #
class RackRoleListView(generics.ListAPIView): class RackRoleViewSet(ModelViewSet):
""" """
List all rack roles List and retrieve rack roles
"""
queryset = RackRole.objects.all()
serializer_class = serializers.RackRoleSerializer
class RackRoleDetailView(generics.RetrieveAPIView):
"""
Retrieve a single rack role
""" """
queryset = RackRole.objects.all() queryset = RackRole.objects.all()
serializer_class = serializers.RackRoleSerializer serializer_class = serializers.RackRoleSerializer
@ -87,28 +63,18 @@ class RackRoleDetailView(generics.RetrieveAPIView):
# Racks # Racks
# #
class RackListView(CustomFieldModelAPIView, generics.ListAPIView): class RackViewSet(CustomFieldModelViewSet):
""" """
List racks (filterable) List and retrieve racks
""" """
queryset = Rack.objects.select_related('site', 'group__site', 'tenant')\ queryset = Rack.objects.select_related('site', 'group__site', 'tenant')
.prefetch_related('custom_field_values__field')
serializer_class = serializers.RackSerializer
filter_class = filters.RackFilter filter_class = filters.RackFilter
def get_serializer_class(self):
if self.action == 'retrieve':
return serializers.RackDetailSerializer
return serializers.RackSerializer
class RackDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
"""
Retrieve a single rack
"""
queryset = Rack.objects.select_related('site', 'group__site', 'tenant')\
.prefetch_related('custom_field_values__field')
serializer_class = serializers.RackDetailSerializer
#
# Rack units
#
class RackUnitListView(APIView): class RackUnitListView(APIView):
""" """
@ -139,17 +105,9 @@ class RackUnitListView(APIView):
# Manufacturers # Manufacturers
# #
class ManufacturerListView(generics.ListAPIView): class ManufacturerViewSet(ModelViewSet):
""" """
List all hardware manufacturers List and retrieve manufacturers
"""
queryset = Manufacturer.objects.all()
serializer_class = serializers.ManufacturerSerializer
class ManufacturerDetailView(generics.RetrieveAPIView):
"""
Retrieve a single hardware manufacturers
""" """
queryset = Manufacturer.objects.all() queryset = Manufacturer.objects.all()
serializer_class = serializers.ManufacturerSerializer serializer_class = serializers.ManufacturerSerializer
@ -159,38 +117,26 @@ class ManufacturerDetailView(generics.RetrieveAPIView):
# Device Types # Device Types
# #
class DeviceTypeListView(CustomFieldModelAPIView, generics.ListAPIView): class DeviceTypeViewSet(CustomFieldModelViewSet):
""" """
List device types (filterable) List and retrieve device types
""" """
queryset = DeviceType.objects.select_related('manufacturer').prefetch_related('custom_field_values__field') queryset = DeviceType.objects.select_related('manufacturer')
serializer_class = serializers.DeviceTypeSerializer
filter_class = filters.DeviceTypeFilter filter_class = filters.DeviceTypeFilter
def get_serializer_class(self):
class DeviceTypeDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView): if self.action == 'retrieve':
""" return serializers.DeviceTypeDetailSerializer
Retrieve a single device type return serializers.DeviceTypeSerializer
"""
queryset = DeviceType.objects.select_related('manufacturer').prefetch_related('custom_field_values__field')
serializer_class = serializers.DeviceTypeDetailSerializer
# #
# Device roles # Device roles
# #
class DeviceRoleListView(generics.ListAPIView): class DeviceRoleViewSet(ModelViewSet):
""" """
List all device roles List and retrieve device roles
"""
queryset = DeviceRole.objects.all()
serializer_class = serializers.DeviceRoleSerializer
class DeviceRoleDetailView(generics.RetrieveAPIView):
"""
Retrieve a single device role
""" """
queryset = DeviceRole.objects.all() queryset = DeviceRole.objects.all()
serializer_class = serializers.DeviceRoleSerializer serializer_class = serializers.DeviceRoleSerializer
@ -200,17 +146,9 @@ class DeviceRoleDetailView(generics.RetrieveAPIView):
# Platforms # Platforms
# #
class PlatformListView(generics.ListAPIView): class PlatformViewSet(ModelViewSet):
""" """
List all platforms List and retrieve platforms
"""
queryset = Platform.objects.all()
serializer_class = serializers.PlatformSerializer
class PlatformDetailView(generics.RetrieveAPIView):
"""
Retrieve a single platform
""" """
queryset = Platform.objects.all() queryset = Platform.objects.all()
serializer_class = serializers.PlatformSerializer serializer_class = serializers.PlatformSerializer
@ -220,40 +158,31 @@ class PlatformDetailView(generics.RetrieveAPIView):
# Devices # Devices
# #
class DeviceListView(CustomFieldModelAPIView, generics.ListAPIView): class DeviceViewSet(CustomFieldModelViewSet):
""" """
List devices (filterable) List and retrieve devices
""" """
queryset = Device.objects.select_related('device_type__manufacturer', 'device_role', 'tenant', 'platform', queryset = Device.objects.select_related(
'rack__site', 'parent_bay').prefetch_related('primary_ip4__nat_outside', 'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'rack__site', 'parent_bay',
'primary_ip6__nat_outside', ).prefetch_related(
'custom_field_values__field') 'primary_ip4__nat_outside', 'primary_ip6__nat_outside',
)
serializer_class = serializers.DeviceSerializer serializer_class = serializers.DeviceSerializer
filter_class = filters.DeviceFilter filter_class = filters.DeviceFilter
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + [BINDZoneRenderer, FlatJSONRenderer] renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + [BINDZoneRenderer, FlatJSONRenderer]
class DeviceDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
"""
Retrieve a single device
"""
queryset = Device.objects.select_related('device_type__manufacturer', 'device_role', 'tenant', 'platform',
'rack__site', 'parent_bay').prefetch_related('custom_field_values__field')
serializer_class = serializers.DeviceSerializer
# #
# Console ports # Console ports
# #
class ConsolePortListView(generics.ListAPIView): class ConsolePortViewSet(ModelViewSet):
""" """
List console ports (by device) List and retrieve console ports (by device)
""" """
serializer_class = serializers.ConsolePortSerializer serializer_class = serializers.ConsolePortSerializer
def get_queryset(self): def get_queryset(self):
device = get_object_or_404(Device, pk=self.kwargs['pk']) device = get_object_or_404(Device, pk=self.kwargs['pk'])
return ConsolePort.objects.filter(device=device).select_related('cs_port') return ConsolePort.objects.filter(device=device).select_related('cs_port')
@ -268,14 +197,13 @@ class ConsolePortView(generics.RetrieveUpdateDestroyAPIView):
# Console server ports # Console server ports
# #
class ConsoleServerPortListView(generics.ListAPIView): class ConsoleServerPortViewSet(ModelViewSet):
""" """
List console server ports (by device) List and retrieve console server ports (by device)
""" """
serializer_class = serializers.ConsoleServerPortSerializer serializer_class = serializers.ConsoleServerPortSerializer
def get_queryset(self): def get_queryset(self):
device = get_object_or_404(Device, pk=self.kwargs['pk']) device = get_object_or_404(Device, pk=self.kwargs['pk'])
return ConsoleServerPort.objects.filter(device=device).select_related('connected_console') return ConsoleServerPort.objects.filter(device=device).select_related('connected_console')
@ -284,14 +212,13 @@ class ConsoleServerPortListView(generics.ListAPIView):
# Power ports # Power ports
# #
class PowerPortListView(generics.ListAPIView): class PowerPortViewSet(ModelViewSet):
""" """
List power ports (by device) List and retrieve power ports (by device)
""" """
serializer_class = serializers.PowerPortSerializer serializer_class = serializers.PowerPortSerializer
def get_queryset(self): def get_queryset(self):
device = get_object_or_404(Device, pk=self.kwargs['pk']) device = get_object_or_404(Device, pk=self.kwargs['pk'])
return PowerPort.objects.filter(device=device).select_related('power_outlet') return PowerPort.objects.filter(device=device).select_related('power_outlet')
@ -306,14 +233,13 @@ class PowerPortView(generics.RetrieveUpdateDestroyAPIView):
# Power outlets # Power outlets
# #
class PowerOutletListView(generics.ListAPIView): class PowerOutletViewSet(ModelViewSet):
""" """
List power outlets (by device) List and retrieve power outlets (by device)
""" """
serializer_class = serializers.PowerOutletSerializer serializer_class = serializers.PowerOutletSerializer
def get_queryset(self): def get_queryset(self):
device = get_object_or_404(Device, pk=self.kwargs['pk']) device = get_object_or_404(Device, pk=self.kwargs['pk'])
return PowerOutlet.objects.filter(device=device).select_related('connected_port') return PowerOutlet.objects.filter(device=device).select_related('connected_port')
@ -322,9 +248,9 @@ class PowerOutletListView(generics.ListAPIView):
# Interfaces # Interfaces
# #
class InterfaceListView(generics.ListAPIView): class InterfaceViewSet(ModelViewSet):
""" """
List interfaces (by device) List and retrieve interfaces (by device)
""" """
serializer_class = serializers.InterfaceSerializer serializer_class = serializers.InterfaceSerializer
filter_class = filters.InterfaceFilter filter_class = filters.InterfaceFilter
@ -372,14 +298,13 @@ class InterfaceConnectionListView(generics.ListAPIView):
# Device bays # Device bays
# #
class DeviceBayListView(generics.ListAPIView): class DeviceBayViewSet(ModelViewSet):
""" """
List device bays (by device) List and retrieve device bays (by device)
""" """
serializer_class = serializers.DeviceBayNestedSerializer serializer_class = serializers.DeviceBayNestedSerializer
def get_queryset(self): def get_queryset(self):
device = get_object_or_404(Device, pk=self.kwargs['pk']) device = get_object_or_404(Device, pk=self.kwargs['pk'])
return DeviceBay.objects.filter(device=device).select_related('installed_device') return DeviceBay.objects.filter(device=device).select_related('installed_device')
@ -388,14 +313,13 @@ class DeviceBayListView(generics.ListAPIView):
# Modules # Modules
# #
class ModuleListView(generics.ListAPIView): class ModuleViewSet(ModelViewSet):
""" """
List device modules (by device) List and retrieve modules (by device)
""" """
serializer_class = serializers.ModuleSerializer serializer_class = serializers.ModuleSerializer
def get_queryset(self): def get_queryset(self):
device = get_object_or_404(Device, pk=self.kwargs['pk']) device = get_object_or_404(Device, pk=self.kwargs['pk'])
return Module.objects.filter(device=device).select_related('device', 'manufacturer') return Module.objects.filter(device=device).select_related('device', 'manufacturer')
@ -442,8 +366,19 @@ class RelatedConnectionsView(APIView):
super(RelatedConnectionsView, self).__init__() super(RelatedConnectionsView, self).__init__()
# Custom fields # Custom fields
self.content_type = ContentType.objects.get_for_model(Device) content_type = ContentType.objects.get_for_model(Device)
self.custom_fields = self.content_type.custom_fields.prefetch_related('choices') custom_fields = content_type.custom_fields.prefetch_related('choices')
# Cache all relevant CustomFieldChoices. This saves us from having to do a lookup per select field per object.
custom_field_choices = {}
for field in custom_fields:
for cfc in field.choices.all():
custom_field_choices[cfc.id] = cfc.value
self.context = {
'custom_fields': custom_fields,
'custom_field_choices': custom_field_choices,
}
def get(self, request): def get(self, request):
@ -469,7 +404,7 @@ class RelatedConnectionsView(APIView):
# Initialize response skeleton # Initialize response skeleton
response = { response = {
'device': serializers.DeviceSerializer(device, context={'view': self}).data, 'device': serializers.DeviceSerializer(device, context=self.context).data,
'console-ports': [], 'console-ports': [],
'power-ports': [], 'power-ports': [],
'interfaces': [], 'interfaces': [],

View File

@ -82,21 +82,6 @@ class SiteTest(APITestCase):
sorted(self.standard_fields), sorted(self.standard_fields),
) )
def test_get_site_list_rack(self, endpoint='/{}api/dcim/sites/1/racks/'.format(settings.BASE_PATH)):
response = self.client.get(endpoint)
content = json.loads(response.content.decode('utf-8'))
self.assertEqual(response.status_code, status.HTTP_200_OK)
for i in json.loads(response.content.decode('utf-8')):
self.assertEqual(
sorted(i.keys()),
sorted(self.rack_fields),
)
# Check Nested Serializer.
self.assertEqual(
sorted(i.get('site').keys()),
sorted(self.nested_fields),
)
def test_get_site_list_graphs(self, endpoint='/{}api/dcim/sites/1/graphs/'.format(settings.BASE_PATH)): def test_get_site_list_graphs(self, endpoint='/{}api/dcim/sites/1/graphs/'.format(settings.BASE_PATH)):
response = self.client.get(endpoint) response = self.client.get(endpoint)
content = json.loads(response.content.decode('utf-8')) content = json.loads(response.content.decode('utf-8'))
@ -239,6 +224,7 @@ class DeviceTypeTest(APITestCase):
'subdevice_role', 'subdevice_role',
'comments', 'comments',
'custom_fields', 'custom_fields',
'instance_count',
] ]
nested_fields = [ nested_fields = [

View File

@ -27,6 +27,8 @@ class BINDZoneRenderer(renderers.BaseRenderer):
def render(self, data, media_type=None, renderer_context=None): def render(self, data, media_type=None, renderer_context=None):
records = [] records = []
if not isinstance(data, (list, tuple)):
data = (data,)
for record in data: for record in data:
if record.get('name') and record.get('primary_ip'): if record.get('name') and record.get('primary_ip'):
try: try:

View File

@ -12,22 +12,20 @@ class CustomFieldSerializer(serializers.Serializer):
def get_custom_fields(self, obj): def get_custom_fields(self, obj):
# Gather all CustomFields applicable to this object # Gather all CustomFields applicable to this object
fields = {cf.name: None for cf in self.context['view'].custom_fields} fields = {cf.name: None for cf in self.context['custom_fields']}
custom_field_choices = self.context['custom_field_choices']
# Attach any defined CustomFieldValues to their respective CustomFields # Attach any defined CustomFieldValues to their respective CustomFields
for cfv in obj.custom_field_values.all(): for cfv in obj.custom_field_values.all():
# Attempt to suppress database lookups for CustomFieldChoices by using the cached choice set from the view # Attempt to suppress database lookups for CustomFieldChoices by using the cached choice set from the view
# context. # context.
if cfv.field.type == CF_TYPE_SELECT and hasattr(self, 'custom_field_choices'): if cfv.field.type == CF_TYPE_SELECT:
cfc = { cfc = {
'id': int(cfv.serialized_value), 'id': int(cfv.serialized_value),
'value': self.context['view'].custom_field_choices[int(cfv.serialized_value)] 'value': custom_field_choices[int(cfv.serialized_value)]
} }
fields[cfv.field.name] = CustomFieldChoiceSerializer(instance=cfc).data fields[cfv.field.name] = CustomFieldChoiceSerializer(instance=cfc).data
# Fall back to hitting the database in case we're in a view that doesn't inherit CustomFieldModelAPIView.
elif cfv.field.type == CF_TYPE_SELECT:
fields[cfv.field.name] = CustomFieldChoiceSerializer(instance=cfv.value).data
else: else:
fields[cfv.field.name] = cfv.value fields[cfv.field.name] = cfv.value

View File

@ -1,6 +1,7 @@
import graphviz import graphviz
from rest_framework import generics from rest_framework import generics
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db.models import Q from django.db.models import Q
@ -14,22 +15,32 @@ from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_P
from .serializers import GraphSerializer from .serializers import GraphSerializer
class CustomFieldModelAPIView(object): class CustomFieldModelViewSet(ModelViewSet):
""" """
Include the applicable set of CustomField in the view context. Include the applicable set of CustomField in the ModelViewSet context.
""" """
def __init__(self): def get_serializer_context(self):
super(CustomFieldModelAPIView, self).__init__()
self.content_type = ContentType.objects.get_for_model(self.queryset.model) # Gather all custom fields for the model
self.custom_fields = self.content_type.custom_fields.prefetch_related('choices') content_type = ContentType.objects.get_for_model(self.queryset.model)
custom_fields = content_type.custom_fields.prefetch_related('choices')
# Cache all relevant CustomFieldChoices. This saves us from having to do a lookup per select field per object. # Cache all relevant CustomFieldChoices. This saves us from having to do a lookup per select field per object.
custom_field_choices = {} custom_field_choices = {}
for field in self.custom_fields: for field in custom_fields:
for cfc in field.choices.all(): for cfc in field.choices.all():
custom_field_choices[cfc.id] = cfc.value custom_field_choices[cfc.id] = cfc.value
self.custom_field_choices = custom_field_choices custom_field_choices = custom_field_choices
return {
'custom_fields': custom_fields,
'custom_field_choices': custom_field_choices,
}
def get_queryset(self):
# Prefetch custom field values
return super(CustomFieldModelViewSet, self).get_queryset().prefetch_related('custom_field_values__field')
class GraphListView(generics.ListAPIView): class GraphListView(generics.ListAPIView):

View File

@ -6,39 +6,39 @@ from .views import *
urlpatterns = [ urlpatterns = [
# VRFs # VRFs
url(r'^vrfs/$', VRFListView.as_view(), name='vrf_list'), url(r'^vrfs/$', VRFViewSet.as_view({'get': 'list'}), name='vrf_list'),
url(r'^vrfs/(?P<pk>\d+)/$', VRFDetailView.as_view(), name='vrf_detail'), url(r'^vrfs/(?P<pk>\d+)/$', VRFViewSet.as_view({'get': 'retrieve'}), name='vrf_detail'),
# Roles # Roles
url(r'^roles/$', RoleListView.as_view(), name='role_list'), url(r'^roles/$', RoleViewSet.as_view({'get': 'list'}), name='role_list'),
url(r'^roles/(?P<pk>\d+)/$', RoleDetailView.as_view(), name='role_detail'), url(r'^roles/(?P<pk>\d+)/$', RoleViewSet.as_view({'get': 'retrieve'}), name='role_detail'),
# RIRs # RIRs
url(r'^rirs/$', RIRListView.as_view(), name='rir_list'), url(r'^rirs/$', RIRViewSet.as_view({'get': 'list'}), name='rir_list'),
url(r'^rirs/(?P<pk>\d+)/$', RIRDetailView.as_view(), name='rir_detail'), url(r'^rirs/(?P<pk>\d+)/$', RIRViewSet.as_view({'get': 'retrieve'}), name='rir_detail'),
# Aggregates # Aggregates
url(r'^aggregates/$', AggregateListView.as_view(), name='aggregate_list'), url(r'^aggregates/$', AggregateViewSet.as_view({'get': 'list'}), name='aggregate_list'),
url(r'^aggregates/(?P<pk>\d+)/$', AggregateDetailView.as_view(), name='aggregate_detail'), url(r'^aggregates/(?P<pk>\d+)/$', AggregateViewSet.as_view({'get': 'retrieve'}), name='aggregate_detail'),
# Prefixes # Prefixes
url(r'^prefixes/$', PrefixListView.as_view(), name='prefix_list'), url(r'^prefixes/$', PrefixViewSet.as_view({'get': 'list'}), name='prefix_list'),
url(r'^prefixes/(?P<pk>\d+)/$', PrefixDetailView.as_view(), name='prefix_detail'), url(r'^prefixes/(?P<pk>\d+)/$', PrefixViewSet.as_view({'get': 'retrieve'}), name='prefix_detail'),
# IP addresses # IP addresses
url(r'^ip-addresses/$', IPAddressListView.as_view(), name='ipaddress_list'), url(r'^ip-addresses/$', IPAddressViewSet.as_view({'get': 'list'}), name='ipaddress_list'),
url(r'^ip-addresses/(?P<pk>\d+)/$', IPAddressDetailView.as_view(), name='ipaddress_detail'), url(r'^ip-addresses/(?P<pk>\d+)/$', IPAddressViewSet.as_view({'get': 'retrieve'}), name='ipaddress_detail'),
# VLAN groups # VLAN groups
url(r'^vlan-groups/$', VLANGroupListView.as_view(), name='vlangroup_list'), url(r'^vlan-groups/$', VLANGroupViewSet.as_view({'get': 'list'}), name='vlangroup_list'),
url(r'^vlan-groups/(?P<pk>\d+)/$', VLANGroupDetailView.as_view(), name='vlangroup_detail'), url(r'^vlan-groups/(?P<pk>\d+)/$', VLANGroupViewSet.as_view({'get': 'retrieve'}), name='vlangroup_detail'),
# VLANs # VLANs
url(r'^vlans/$', VLANListView.as_view(), name='vlan_list'), url(r'^vlans/$', VLANViewSet.as_view({'get': 'list'}), name='vlan_list'),
url(r'^vlans/(?P<pk>\d+)/$', VLANDetailView.as_view(), name='vlan_detail'), url(r'^vlans/(?P<pk>\d+)/$', VLANViewSet.as_view({'get': 'retrieve'}), name='vlan_detail'),
# Services # Services
url(r'^services/$', ServiceListView.as_view(), name='service_list'), url(r'^services/$', ServiceViewSet.as_view({'get': 'list'}), name='service_list'),
url(r'^services/(?P<pk>\d+)/$', ServiceDetailView.as_view(), name='service_detail'), url(r'^services/(?P<pk>\d+)/$', ServiceViewSet.as_view({'get': 'retrieve'}), name='service_detail'),
] ]

View File

@ -1,9 +1,9 @@
from rest_framework import generics from rest_framework.viewsets import ModelViewSet
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 ipam import filters from ipam import filters
from extras.api.views import CustomFieldModelAPIView from extras.api.views import CustomFieldModelViewSet
from . import serializers from . import serializers
@ -11,38 +11,22 @@ from . import serializers
# VRFs # VRFs
# #
class VRFListView(CustomFieldModelAPIView, generics.ListAPIView): class VRFViewSet(CustomFieldModelViewSet):
""" """
List all VRFs List and retrieve VRFs
""" """
queryset = VRF.objects.select_related('tenant').prefetch_related('custom_field_values__field') queryset = VRF.objects.select_related('tenant')
serializer_class = serializers.VRFSerializer serializer_class = serializers.VRFSerializer
filter_class = filters.VRFFilter filter_class = filters.VRFFilter
class VRFDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
"""
Retrieve a single VRF
"""
queryset = VRF.objects.select_related('tenant').prefetch_related('custom_field_values__field')
serializer_class = serializers.VRFSerializer
# #
# Roles # Roles
# #
class RoleListView(generics.ListAPIView): class RoleViewSet(ModelViewSet):
""" """
List all roles List and retrieve prefix/VLAN roles
"""
queryset = Role.objects.all()
serializer_class = serializers.RoleSerializer
class RoleDetailView(generics.RetrieveAPIView):
"""
Retrieve a single role
""" """
queryset = Role.objects.all() queryset = Role.objects.all()
serializer_class = serializers.RoleSerializer serializer_class = serializers.RoleSerializer
@ -52,17 +36,9 @@ class RoleDetailView(generics.RetrieveAPIView):
# RIRs # RIRs
# #
class RIRListView(generics.ListAPIView): class RIRViewSet(ModelViewSet):
""" """
List all RIRs List and retrieve RIRs
"""
queryset = RIR.objects.all()
serializer_class = serializers.RIRSerializer
class RIRDetailView(generics.RetrieveAPIView):
"""
Retrieve a single RIR
""" """
queryset = RIR.objects.all() queryset = RIR.objects.all()
serializer_class = serializers.RIRSerializer serializer_class = serializers.RIRSerializer
@ -72,129 +48,75 @@ class RIRDetailView(generics.RetrieveAPIView):
# Aggregates # Aggregates
# #
class AggregateListView(CustomFieldModelAPIView, generics.ListAPIView): class AggregateViewSet(CustomFieldModelViewSet):
""" """
List aggregates (filterable) List and retrieve aggregates
""" """
queryset = Aggregate.objects.select_related('rir').prefetch_related('custom_field_values__field') queryset = Aggregate.objects.select_related('rir')
serializer_class = serializers.AggregateSerializer serializer_class = serializers.AggregateSerializer
filter_class = filters.AggregateFilter filter_class = filters.AggregateFilter
class AggregateDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
"""
Retrieve a single aggregate
"""
queryset = Aggregate.objects.select_related('rir').prefetch_related('custom_field_values__field')
serializer_class = serializers.AggregateSerializer
# #
# Prefixes # Prefixes
# #
class PrefixListView(CustomFieldModelAPIView, generics.ListAPIView): class PrefixViewSet(CustomFieldModelViewSet):
""" """
List prefixes (filterable) List and retrieve prefixes
""" """
queryset = Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')\ queryset = Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
.prefetch_related('custom_field_values__field')
serializer_class = serializers.PrefixSerializer serializer_class = serializers.PrefixSerializer
filter_class = filters.PrefixFilter filter_class = filters.PrefixFilter
class PrefixDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
"""
Retrieve a single prefix
"""
queryset = Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')\
.prefetch_related('custom_field_values__field')
serializer_class = serializers.PrefixSerializer
# #
# IP addresses # IP addresses
# #
class IPAddressListView(CustomFieldModelAPIView, generics.ListAPIView): class IPAddressViewSet(CustomFieldModelViewSet):
""" """
List IP addresses (filterable) List and retrieve IP addresses
""" """
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device', 'nat_inside')\ queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device', 'nat_inside')
.prefetch_related('nat_outside', 'custom_field_values__field')
serializer_class = serializers.IPAddressSerializer serializer_class = serializers.IPAddressSerializer
filter_class = filters.IPAddressFilter filter_class = filters.IPAddressFilter
class IPAddressDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
"""
Retrieve a single IP address
"""
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device', 'nat_inside')\
.prefetch_related('nat_outside', 'custom_field_values__field')
serializer_class = serializers.IPAddressSerializer
# #
# VLAN groups # VLAN groups
# #
class VLANGroupListView(generics.ListAPIView): class VLANGroupViewSet(ModelViewSet):
""" """
List all VLAN groups List and retrieve VLAN groups
""" """
queryset = VLANGroup.objects.select_related('site') queryset = VLANGroup.objects.select_related('site')
serializer_class = serializers.VLANGroupSerializer serializer_class = serializers.VLANGroupSerializer
filter_class = filters.VLANGroupFilter filter_class = filters.VLANGroupFilter
class VLANGroupDetailView(generics.RetrieveAPIView):
"""
Retrieve a single VLAN group
"""
queryset = VLANGroup.objects.select_related('site')
serializer_class = serializers.VLANGroupSerializer
# #
# VLANs # VLANs
# #
class VLANListView(CustomFieldModelAPIView, generics.ListAPIView): class VLANViewSet(CustomFieldModelViewSet):
""" """
List VLANs (filterable) List and retrieve VLANs
""" """
queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role')\ queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role')
.prefetch_related('custom_field_values__field')
serializer_class = serializers.VLANSerializer serializer_class = serializers.VLANSerializer
filter_class = filters.VLANFilter filter_class = filters.VLANFilter
class VLANDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
"""
Retrieve a single VLAN
"""
queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role')\
.prefetch_related('custom_field_values__field')
serializer_class = serializers.VLANSerializer
# #
# Services # Services
# #
class ServiceListView(generics.ListAPIView): class ServiceViewSet(ModelViewSet):
""" """
List services (filterable) List and retrieve services
""" """
queryset = Service.objects.select_related('device').prefetch_related('ipaddresses') queryset = Service.objects.select_related('device').prefetch_related('ipaddresses')
serializer_class = serializers.ServiceSerializer serializer_class = serializers.ServiceSerializer
filter_class = filters.ServiceFilter filter_class = filters.ServiceFilter
class ServiceDetailView(generics.RetrieveAPIView):
"""
Retrieve a single service
"""
queryset = Service.objects.select_related('device').prefetch_related('ipaddresses')
serializer_class = serializers.ServiceSerializer

View File

@ -5,14 +5,14 @@ from .views import *
urlpatterns = [ urlpatterns = [
# Secret roles
url(r'^secret-roles/$', SecretRoleViewSet.as_view({'get': 'list'}), name='secretrole_list'),
url(r'^secret-roles/(?P<pk>\d+)/$', SecretRoleViewSet.as_view({'get': 'retrieve'}), name='secretrole_detail'),
# Secrets # Secrets
url(r'^secrets/$', SecretListView.as_view(), name='secret_list'), url(r'^secrets/$', SecretListView.as_view(), name='secret_list'),
url(r'^secrets/(?P<pk>\d+)/$', SecretDetailView.as_view(), name='secret_detail'), url(r'^secrets/(?P<pk>\d+)/$', SecretDetailView.as_view(), name='secret_detail'),
# Secret roles
url(r'^secret-roles/$', SecretRoleListView.as_view(), name='secretrole_list'),
url(r'^secret-roles/(?P<pk>\d+)/$', SecretRoleDetailView.as_view(), name='secretrole_detail'),
# Miscellaneous # Miscellaneous
url(r'^generate-keys/$', RSAKeyGeneratorView.as_view(), name='generate_keys'), url(r'^generate-keys/$', RSAKeyGeneratorView.as_view(), name='generate_keys'),

View File

@ -9,6 +9,7 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from extras.api.renderers import FormlessBrowsableAPIRenderer, FreeRADIUSClientsRenderer from extras.api.renderers import FormlessBrowsableAPIRenderer, FreeRADIUSClientsRenderer
from secrets.filters import SecretFilter from secrets.filters import SecretFilter
@ -22,23 +23,22 @@ ERR_USERKEY_INACTIVE = "UserKey has not been activated for decryption."
ERR_PRIVKEY_INVALID = "Invalid private key." ERR_PRIVKEY_INVALID = "Invalid private key."
class SecretRoleListView(generics.ListAPIView): #
# Secret Roles
#
class SecretRoleViewSet(ModelViewSet):
""" """
List all secret roles List and retrieve secret roles
""" """
queryset = SecretRole.objects.all() queryset = SecretRole.objects.all()
serializer_class = serializers.SecretRoleSerializer serializer_class = serializers.SecretRoleSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
class SecretRoleDetailView(generics.RetrieveAPIView): #
""" # Secrets
Retrieve a single secret role #
"""
queryset = SecretRole.objects.all()
serializer_class = serializers.SecretRoleSerializer
permission_classes = [IsAuthenticated]
class SecretListView(generics.GenericAPIView): class SecretListView(generics.GenericAPIView):
""" """

View File

@ -6,11 +6,11 @@ from .views import *
urlpatterns = [ urlpatterns = [
# Tenant groups # Tenant groups
url(r'^tenant-groups/$', TenantGroupListView.as_view(), name='tenantgroup_list'), url(r'^tenant-groups/$', TenantGroupViewSet.as_view({'get': 'list'}), name='tenantgroup_list'),
url(r'^tenant-groups/(?P<pk>\d+)/$', TenantGroupDetailView.as_view(), name='tenantgroup_detail'), url(r'^tenant-groups/(?P<pk>\d+)/$', TenantGroupViewSet.as_view({'get': 'retrieve'}), name='tenantgroup_detail'),
# Tenants # Tenants
url(r'^tenants/$', TenantListView.as_view(), name='tenant_list'), url(r'^tenants/$', TenantViewSet.as_view({'get': 'list'}), name='tenant_list'),
url(r'^tenants/(?P<pk>\d+)/$', TenantDetailView.as_view(), name='tenant_detail'), url(r'^tenants/(?P<pk>\d+)/$', TenantViewSet.as_view({'get': 'retrieve'}), name='tenant_detail'),
] ]

View File

@ -1,40 +1,32 @@
from rest_framework import generics from rest_framework.viewsets import ModelViewSet
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from tenancy.filters import TenantFilter from tenancy.filters import TenantFilter
from extras.api.views import CustomFieldModelAPIView from extras.api.views import CustomFieldModelViewSet
from . import serializers from . import serializers
class TenantGroupListView(generics.ListAPIView): #
# Tenant Groups
#
class TenantGroupViewSet(ModelViewSet):
""" """
List all tenant groups List and retrieve tenant groups
""" """
queryset = TenantGroup.objects.all() queryset = TenantGroup.objects.all()
serializer_class = serializers.TenantGroupSerializer serializer_class = serializers.TenantGroupSerializer
class TenantGroupDetailView(generics.RetrieveAPIView): #
""" # Tenants
Retrieve a single circuit type #
"""
queryset = TenantGroup.objects.all()
serializer_class = serializers.TenantGroupSerializer
class TenantViewSet(CustomFieldModelViewSet):
class TenantListView(CustomFieldModelAPIView, generics.ListAPIView):
""" """
List tenants (filterable) List and retrieve tenants
""" """
queryset = Tenant.objects.select_related('group').prefetch_related('custom_field_values__field') queryset = Tenant.objects.select_related('group')
serializer_class = serializers.TenantSerializer serializer_class = serializers.TenantSerializer
filter_class = TenantFilter filter_class = TenantFilter
class TenantDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
"""
Retrieve a single tenant
"""
queryset = Tenant.objects.select_related('group').prefetch_related('custom_field_values__field')
serializer_class = serializers.TenantSerializer