mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 20:12:00 -06:00
Extended API to include custom fields
This commit is contained in:
parent
b14afaa687
commit
76f0463290
@ -2,6 +2,7 @@ from rest_framework import serializers
|
||||
|
||||
from circuits.models import Provider, CircuitType, Circuit
|
||||
from dcim.api.serializers import SiteNestedSerializer, InterfaceNestedSerializer
|
||||
from extras.api.serializers import CustomFieldsSerializer
|
||||
from tenancy.api.serializers import TenantNestedSerializer
|
||||
|
||||
|
||||
@ -9,11 +10,12 @@ from tenancy.api.serializers import TenantNestedSerializer
|
||||
# Providers
|
||||
#
|
||||
|
||||
class ProviderSerializer(serializers.ModelSerializer):
|
||||
class ProviderSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Provider
|
||||
fields = ['id', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments']
|
||||
fields = ['id', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments',
|
||||
'custom_fields']
|
||||
|
||||
|
||||
class ProviderNestedSerializer(ProviderSerializer):
|
||||
@ -43,7 +45,7 @@ class CircuitTypeNestedSerializer(CircuitTypeSerializer):
|
||||
# Circuits
|
||||
#
|
||||
|
||||
class CircuitSerializer(serializers.ModelSerializer):
|
||||
class CircuitSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
provider = ProviderNestedSerializer()
|
||||
type = CircuitTypeNestedSerializer()
|
||||
tenant = TenantNestedSerializer()
|
||||
@ -53,7 +55,7 @@ class CircuitSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Circuit
|
||||
fields = ['id', 'cid', 'provider', 'type', 'tenant', 'site', 'interface', 'install_date', 'port_speed',
|
||||
'upstream_speed', 'commit_rate', 'xconnect_id', 'comments']
|
||||
'upstream_speed', 'commit_rate', 'xconnect_id', 'comments', 'custom_fields']
|
||||
|
||||
|
||||
class CircuitNestedSerializer(CircuitSerializer):
|
||||
|
@ -3,22 +3,23 @@ from rest_framework import generics
|
||||
from circuits.models import Provider, CircuitType, Circuit
|
||||
from circuits.filters import CircuitFilter
|
||||
|
||||
from extras.api.views import CustomFieldModelAPIView
|
||||
from . import serializers
|
||||
|
||||
|
||||
class ProviderListView(generics.ListAPIView):
|
||||
class ProviderListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List all providers
|
||||
"""
|
||||
queryset = Provider.objects.all()
|
||||
queryset = Provider.objects.prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.ProviderSerializer
|
||||
|
||||
|
||||
class ProviderDetailView(generics.RetrieveAPIView):
|
||||
class ProviderDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single provider
|
||||
"""
|
||||
queryset = Provider.objects.all()
|
||||
queryset = Provider.objects.prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.ProviderSerializer
|
||||
|
||||
|
||||
@ -38,18 +39,20 @@ class CircuitTypeDetailView(generics.RetrieveAPIView):
|
||||
serializer_class = serializers.CircuitTypeSerializer
|
||||
|
||||
|
||||
class CircuitListView(generics.ListAPIView):
|
||||
class CircuitListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List circuits (filterable)
|
||||
"""
|
||||
queryset = Circuit.objects.select_related('type', 'tenant', 'provider', 'site', 'interface__device')
|
||||
queryset = Circuit.objects.select_related('type', 'tenant', 'provider', 'site', 'interface__device')\
|
||||
.prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.CircuitSerializer
|
||||
filter_class = CircuitFilter
|
||||
|
||||
|
||||
class CircuitDetailView(generics.RetrieveAPIView):
|
||||
class CircuitDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single circuit
|
||||
"""
|
||||
queryset = Circuit.objects.select_related('type', 'tenant', 'provider', 'site', 'interface__device')
|
||||
queryset = Circuit.objects.select_related('type', 'tenant', 'provider', 'site', 'interface__device')\
|
||||
.prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.CircuitSerializer
|
||||
|
@ -1,9 +1,10 @@
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
|
||||
from dcim.fields import ASNField
|
||||
from dcim.models import Site, Interface
|
||||
from extras.models import CustomFieldModel
|
||||
from extras.models import CustomFieldModel, CustomFieldValue
|
||||
from tenancy.models import Tenant
|
||||
from utilities.models import CreatedUpdatedModel
|
||||
|
||||
@ -21,6 +22,7 @@ class Provider(CreatedUpdatedModel, CustomFieldModel):
|
||||
noc_contact = models.TextField(blank=True, verbose_name='NOC contact')
|
||||
admin_contact = models.TextField(blank=True, verbose_name='Admin contact')
|
||||
comments = models.TextField(blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
@ -79,6 +81,7 @@ class Circuit(CreatedUpdatedModel, CustomFieldModel):
|
||||
xconnect_id = models.CharField(max_length=50, blank=True, verbose_name='Cross-connect ID')
|
||||
pp_info = models.CharField(max_length=100, blank=True, verbose_name='Patch panel/port(s)')
|
||||
comments = models.TextField(blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
class Meta:
|
||||
ordering = ['provider', 'cid']
|
||||
|
@ -6,6 +6,7 @@ from dcim.models import (
|
||||
DeviceRole, Interface, InterfaceConnection, InterfaceTemplate, Manufacturer, Module, Platform, PowerOutlet,
|
||||
PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, RackRole, RACK_FACE_FRONT, RACK_FACE_REAR, Site,
|
||||
)
|
||||
from extras.api.serializers import CustomFieldsSerializer
|
||||
from tenancy.api.serializers import TenantNestedSerializer
|
||||
|
||||
|
||||
@ -13,13 +14,13 @@ from tenancy.api.serializers import TenantNestedSerializer
|
||||
# Sites
|
||||
#
|
||||
|
||||
class SiteSerializer(serializers.ModelSerializer):
|
||||
class SiteSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
tenant = TenantNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Site
|
||||
fields = ['id', 'name', 'slug', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address', 'comments',
|
||||
'count_prefixes', 'count_vlans', 'count_racks', 'count_devices', 'count_circuits']
|
||||
'custom_fields', 'count_prefixes', 'count_vlans', 'count_racks', 'count_devices', 'count_circuits']
|
||||
|
||||
|
||||
class SiteNestedSerializer(SiteSerializer):
|
||||
@ -68,7 +69,7 @@ class RackRoleNestedSerializer(RackRoleSerializer):
|
||||
#
|
||||
|
||||
|
||||
class RackSerializer(serializers.ModelSerializer):
|
||||
class RackSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
site = SiteNestedSerializer()
|
||||
group = RackGroupNestedSerializer()
|
||||
tenant = TenantNestedSerializer()
|
||||
@ -77,7 +78,7 @@ class RackSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Rack
|
||||
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'role', 'type', 'width',
|
||||
'u_height', 'comments']
|
||||
'u_height', 'comments', 'custom_fields']
|
||||
|
||||
|
||||
class RackNestedSerializer(RackSerializer):
|
||||
@ -237,7 +238,7 @@ class DeviceIPAddressNestedSerializer(serializers.ModelSerializer):
|
||||
fields = ['id', 'family', 'address']
|
||||
|
||||
|
||||
class DeviceSerializer(serializers.ModelSerializer):
|
||||
class DeviceSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
device_type = DeviceTypeNestedSerializer()
|
||||
device_role = DeviceRoleNestedSerializer()
|
||||
tenant = TenantNestedSerializer()
|
||||
@ -252,7 +253,7 @@ class DeviceSerializer(serializers.ModelSerializer):
|
||||
model = Device
|
||||
fields = ['id', 'name', 'display_name', 'device_type', 'device_role', 'tenant', 'platform', 'serial',
|
||||
'asset_tag', 'rack', 'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4',
|
||||
'primary_ip6', 'comments']
|
||||
'primary_ip6', 'comments', 'custom_fields']
|
||||
|
||||
def get_parent_device(self, obj):
|
||||
try:
|
||||
|
@ -13,29 +13,30 @@ from dcim.models import (
|
||||
InterfaceConnection, Manufacturer, Module, Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, Site,
|
||||
)
|
||||
from dcim import filters
|
||||
from .exceptions import MissingFilterException
|
||||
from . import serializers
|
||||
from extras.api.views import CustomFieldModelAPIView
|
||||
from extras.api.renderers import BINDZoneRenderer, FlatJSONRenderer
|
||||
from utilities.api import ServiceUnavailable
|
||||
from .exceptions import MissingFilterException
|
||||
from . import serializers
|
||||
|
||||
|
||||
#
|
||||
# Sites
|
||||
#
|
||||
|
||||
class SiteListView(generics.ListAPIView):
|
||||
class SiteListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List all sites
|
||||
"""
|
||||
queryset = Site.objects.select_related('tenant')
|
||||
queryset = Site.objects.select_related('tenant').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.SiteSerializer
|
||||
|
||||
|
||||
class SiteDetailView(generics.RetrieveAPIView):
|
||||
class SiteDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single site
|
||||
"""
|
||||
queryset = Site.objects.select_related('tenant')
|
||||
queryset = Site.objects.select_related('tenant').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.SiteSerializer
|
||||
|
||||
|
||||
@ -84,20 +85,20 @@ class RackRoleDetailView(generics.RetrieveAPIView):
|
||||
# Racks
|
||||
#
|
||||
|
||||
class RackListView(generics.ListAPIView):
|
||||
class RackListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List racks (filterable)
|
||||
"""
|
||||
queryset = Rack.objects.select_related('site', 'group', 'tenant')
|
||||
queryset = Rack.objects.select_related('site', 'group__site', 'tenant').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.RackSerializer
|
||||
filter_class = filters.RackFilter
|
||||
|
||||
|
||||
class RackDetailView(generics.RetrieveAPIView):
|
||||
class RackDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single rack
|
||||
"""
|
||||
queryset = Rack.objects.select_related('site', 'group', 'tenant')
|
||||
queryset = Rack.objects.select_related('site', 'group__site', 'tenant').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.RackDetailSerializer
|
||||
|
||||
|
||||
@ -209,24 +210,25 @@ class PlatformDetailView(generics.RetrieveAPIView):
|
||||
# Devices
|
||||
#
|
||||
|
||||
class DeviceListView(generics.ListAPIView):
|
||||
class DeviceListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List devices (filterable)
|
||||
"""
|
||||
queryset = Device.objects.select_related('device_type__manufacturer', 'device_role', 'tenant', 'platform',
|
||||
'rack__site', 'parent_bay').prefetch_related('primary_ip4__nat_outside',
|
||||
'primary_ip6__nat_outside')
|
||||
'primary_ip6__nat_outside',
|
||||
'custom_field_values')
|
||||
serializer_class = serializers.DeviceSerializer
|
||||
filter_class = filters.DeviceFilter
|
||||
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + [BINDZoneRenderer, FlatJSONRenderer]
|
||||
|
||||
|
||||
class DeviceDetailView(generics.RetrieveAPIView):
|
||||
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')
|
||||
'rack__site', 'parent_bay').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.DeviceSerializer
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@ from collections import OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.core.exceptions import MultipleObjectsReturned, ValidationError
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
@ -228,6 +229,7 @@ class Site(CreatedUpdatedModel, CustomFieldModel):
|
||||
physical_address = models.CharField(max_length=200, blank=True)
|
||||
shipping_address = models.CharField(max_length=200, blank=True)
|
||||
comments = models.TextField(blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
objects = SiteManager()
|
||||
|
||||
@ -339,6 +341,7 @@ class Rack(CreatedUpdatedModel, CustomFieldModel):
|
||||
u_height = models.PositiveSmallIntegerField(default=42, verbose_name='Height (U)',
|
||||
validators=[MinValueValidator(1), MaxValueValidator(100)])
|
||||
comments = models.TextField(blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
objects = RackManager()
|
||||
|
||||
@ -752,6 +755,7 @@ class Device(CreatedUpdatedModel, CustomFieldModel):
|
||||
primary_ip6 = models.OneToOneField('ipam.IPAddress', related_name='primary_ip6_for', on_delete=models.SET_NULL,
|
||||
blank=True, null=True, verbose_name='Primary IPv6')
|
||||
comments = models.TextField(blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
objects = DeviceManager()
|
||||
|
||||
|
@ -1,6 +1,29 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from extras.models import Graph
|
||||
from extras.models import CF_TYPE_SELECT, CustomFieldChoice, Graph
|
||||
|
||||
|
||||
class CustomFieldsSerializer(serializers.Serializer):
|
||||
"""
|
||||
Extends a ModelSerializer to render any CustomFields and their values associated with an object.
|
||||
"""
|
||||
custom_fields = serializers.SerializerMethodField()
|
||||
|
||||
def get_custom_fields(self, obj):
|
||||
fields = {cf.name: None for cf in self.context['view'].custom_fields}
|
||||
for cfv in obj.custom_field_values.all():
|
||||
if cfv.field.type == CF_TYPE_SELECT:
|
||||
fields[cfv.field.name] = CustomFieldChoiceSerializer(instance=cfv.value).data
|
||||
else:
|
||||
fields[cfv.field.name] = cfv.value
|
||||
return fields
|
||||
|
||||
|
||||
class CustomFieldChoiceSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = CustomFieldChoice
|
||||
fields = ['id', 'value']
|
||||
|
||||
|
||||
class GraphSerializer(serializers.ModelSerializer):
|
||||
|
@ -1,9 +1,8 @@
|
||||
import graphviz
|
||||
from rest_framework import generics
|
||||
from rest_framework.views import APIView
|
||||
import tempfile
|
||||
from wsgiref.util import FileWrapper
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db.models import Q
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
@ -15,6 +14,17 @@ from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_P
|
||||
from .serializers import GraphSerializer
|
||||
|
||||
|
||||
class CustomFieldModelAPIView(object):
|
||||
"""
|
||||
Include the applicable set of CustomField in the view context.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(CustomFieldModelAPIView, self).__init__()
|
||||
self.content_type = ContentType.objects.get_for_model(self.queryset.model)
|
||||
self.custom_fields = self.content_type.custom_fields.all()
|
||||
|
||||
|
||||
class GraphListView(generics.ListAPIView):
|
||||
"""
|
||||
Returns a list of relevant graphs
|
||||
|
@ -1,6 +1,7 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from dcim.api.serializers import SiteNestedSerializer, InterfaceNestedSerializer
|
||||
from extras.api.serializers import CustomFieldsSerializer
|
||||
from ipam.models import VRF, Role, RIR, Aggregate, Prefix, IPAddress, VLAN, VLANGroup
|
||||
from tenancy.api.serializers import TenantNestedSerializer
|
||||
|
||||
@ -9,12 +10,12 @@ from tenancy.api.serializers import TenantNestedSerializer
|
||||
# VRFs
|
||||
#
|
||||
|
||||
class VRFSerializer(serializers.ModelSerializer):
|
||||
class VRFSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
tenant = TenantNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = VRF
|
||||
fields = ['id', 'name', 'rd', 'tenant', 'enforce_unique', 'description']
|
||||
fields = ['id', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'custom_fields']
|
||||
|
||||
|
||||
class VRFNestedSerializer(VRFSerializer):
|
||||
@ -70,12 +71,12 @@ class RIRNestedSerializer(RIRSerializer):
|
||||
# Aggregates
|
||||
#
|
||||
|
||||
class AggregateSerializer(serializers.ModelSerializer):
|
||||
class AggregateSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
rir = RIRNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Aggregate
|
||||
fields = ['id', 'family', 'prefix', 'rir', 'date_added', 'description']
|
||||
fields = ['id', 'family', 'prefix', 'rir', 'date_added', 'description', 'custom_fields']
|
||||
|
||||
|
||||
class AggregateNestedSerializer(AggregateSerializer):
|
||||
@ -106,7 +107,7 @@ class VLANGroupNestedSerializer(VLANGroupSerializer):
|
||||
# VLANs
|
||||
#
|
||||
|
||||
class VLANSerializer(serializers.ModelSerializer):
|
||||
class VLANSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
site = SiteNestedSerializer()
|
||||
group = VLANGroupNestedSerializer()
|
||||
tenant = TenantNestedSerializer()
|
||||
@ -114,7 +115,8 @@ class VLANSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = VLAN
|
||||
fields = ['id', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'display_name']
|
||||
fields = ['id', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'display_name',
|
||||
'custom_fields']
|
||||
|
||||
|
||||
class VLANNestedSerializer(VLANSerializer):
|
||||
@ -127,7 +129,7 @@ class VLANNestedSerializer(VLANSerializer):
|
||||
# Prefixes
|
||||
#
|
||||
|
||||
class PrefixSerializer(serializers.ModelSerializer):
|
||||
class PrefixSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
site = SiteNestedSerializer()
|
||||
vrf = VRFTenantSerializer()
|
||||
tenant = TenantNestedSerializer()
|
||||
@ -136,7 +138,8 @@ class PrefixSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Prefix
|
||||
fields = ['id', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'description']
|
||||
fields = ['id', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'description',
|
||||
'custom_fields']
|
||||
|
||||
|
||||
class PrefixNestedSerializer(PrefixSerializer):
|
||||
@ -149,14 +152,15 @@ class PrefixNestedSerializer(PrefixSerializer):
|
||||
# IP addresses
|
||||
#
|
||||
|
||||
class IPAddressSerializer(serializers.ModelSerializer):
|
||||
class IPAddressSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
vrf = VRFTenantSerializer()
|
||||
tenant = TenantNestedSerializer()
|
||||
interface = InterfaceNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = IPAddress
|
||||
fields = ['id', 'family', 'address', 'vrf', 'tenant', 'interface', 'description', 'nat_inside', 'nat_outside']
|
||||
fields = ['id', 'family', 'address', 'vrf', 'tenant', 'interface', 'description', 'nat_inside', 'nat_outside',
|
||||
'custom_fields']
|
||||
|
||||
|
||||
class IPAddressNestedSerializer(IPAddressSerializer):
|
||||
|
@ -3,6 +3,7 @@ from rest_framework import generics
|
||||
from ipam.models import VRF, Role, RIR, Aggregate, Prefix, IPAddress, VLAN, VLANGroup
|
||||
from ipam import filters
|
||||
|
||||
from extras.api.views import CustomFieldModelAPIView
|
||||
from . import serializers
|
||||
|
||||
|
||||
@ -10,20 +11,20 @@ from . import serializers
|
||||
# VRFs
|
||||
#
|
||||
|
||||
class VRFListView(generics.ListAPIView):
|
||||
class VRFListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List all VRFs
|
||||
"""
|
||||
queryset = VRF.objects.select_related('tenant')
|
||||
queryset = VRF.objects.select_related('tenant').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.VRFSerializer
|
||||
filter_class = filters.VRFFilter
|
||||
|
||||
|
||||
class VRFDetailView(generics.RetrieveAPIView):
|
||||
class VRFDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single VRF
|
||||
"""
|
||||
queryset = VRF.objects.select_related('tenant')
|
||||
queryset = VRF.objects.select_related('tenant').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.VRFSerializer
|
||||
|
||||
|
||||
@ -71,20 +72,20 @@ class RIRDetailView(generics.RetrieveAPIView):
|
||||
# Aggregates
|
||||
#
|
||||
|
||||
class AggregateListView(generics.ListAPIView):
|
||||
class AggregateListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List aggregates (filterable)
|
||||
"""
|
||||
queryset = Aggregate.objects.select_related('rir')
|
||||
queryset = Aggregate.objects.select_related('rir').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.AggregateSerializer
|
||||
filter_class = filters.AggregateFilter
|
||||
|
||||
|
||||
class AggregateDetailView(generics.RetrieveAPIView):
|
||||
class AggregateDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single aggregate
|
||||
"""
|
||||
queryset = Aggregate.objects.select_related('rir')
|
||||
queryset = Aggregate.objects.select_related('rir').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.AggregateSerializer
|
||||
|
||||
|
||||
@ -92,20 +93,22 @@ class AggregateDetailView(generics.RetrieveAPIView):
|
||||
# Prefixes
|
||||
#
|
||||
|
||||
class PrefixListView(generics.ListAPIView):
|
||||
class PrefixListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List prefixes (filterable)
|
||||
"""
|
||||
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')
|
||||
serializer_class = serializers.PrefixSerializer
|
||||
filter_class = filters.PrefixFilter
|
||||
|
||||
|
||||
class PrefixDetailView(generics.RetrieveAPIView):
|
||||
class PrefixDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single prefix
|
||||
"""
|
||||
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')
|
||||
serializer_class = serializers.PrefixSerializer
|
||||
|
||||
|
||||
@ -113,22 +116,22 @@ class PrefixDetailView(generics.RetrieveAPIView):
|
||||
# IP addresses
|
||||
#
|
||||
|
||||
class IPAddressListView(generics.ListAPIView):
|
||||
class IPAddressListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List IP addresses (filterable)
|
||||
"""
|
||||
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device', 'nat_inside')\
|
||||
.prefetch_related('nat_outside')
|
||||
.prefetch_related('nat_outside', 'custom_field_values')
|
||||
serializer_class = serializers.IPAddressSerializer
|
||||
filter_class = filters.IPAddressFilter
|
||||
|
||||
|
||||
class IPAddressDetailView(generics.RetrieveAPIView):
|
||||
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')
|
||||
.prefetch_related('nat_outside', 'custom_field_values')
|
||||
serializer_class = serializers.IPAddressSerializer
|
||||
|
||||
|
||||
@ -157,18 +160,18 @@ class VLANGroupDetailView(generics.RetrieveAPIView):
|
||||
# VLANs
|
||||
#
|
||||
|
||||
class VLANListView(generics.ListAPIView):
|
||||
class VLANListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List VLANs (filterable)
|
||||
"""
|
||||
queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role')
|
||||
queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.VLANSerializer
|
||||
filter_class = filters.VLANFilter
|
||||
|
||||
|
||||
class VLANDetailView(generics.RetrieveAPIView):
|
||||
class VLANDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single VLAN
|
||||
"""
|
||||
queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role')
|
||||
queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.VLANSerializer
|
||||
|
@ -1,6 +1,7 @@
|
||||
from netaddr import IPNetwork, cidr_merge
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
@ -8,7 +9,7 @@ from django.db import models
|
||||
from django.db.models.expressions import RawSQL
|
||||
|
||||
from dcim.models import Interface
|
||||
from extras.models import CustomFieldModel
|
||||
from extras.models import CustomFieldModel, CustomFieldValue
|
||||
from tenancy.models import Tenant
|
||||
from utilities.models import CreatedUpdatedModel
|
||||
|
||||
@ -53,6 +54,7 @@ class VRF(CreatedUpdatedModel, CustomFieldModel):
|
||||
enforce_unique = models.BooleanField(default=True, verbose_name='Enforce unique space',
|
||||
help_text="Prevent duplicate prefixes/IP addresses within this VRF")
|
||||
description = models.CharField(max_length=100, blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
@ -105,6 +107,7 @@ class Aggregate(CreatedUpdatedModel, CustomFieldModel):
|
||||
rir = models.ForeignKey('RIR', related_name='aggregates', on_delete=models.PROTECT, verbose_name='RIR')
|
||||
date_added = models.DateField(blank=True, null=True)
|
||||
description = models.CharField(max_length=100, blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
class Meta:
|
||||
ordering = ['family', 'prefix']
|
||||
@ -241,6 +244,7 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel):
|
||||
status = models.PositiveSmallIntegerField('Status', choices=PREFIX_STATUS_CHOICES, default=1)
|
||||
role = models.ForeignKey('Role', related_name='prefixes', on_delete=models.SET_NULL, blank=True, null=True)
|
||||
description = models.CharField(max_length=100, blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
objects = PrefixQuerySet.as_manager()
|
||||
|
||||
@ -332,6 +336,7 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel):
|
||||
nat_inside = models.OneToOneField('self', related_name='nat_outside', on_delete=models.SET_NULL, blank=True,
|
||||
null=True, verbose_name='NAT IP (inside)')
|
||||
description = models.CharField(max_length=100, blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
objects = IPAddressManager()
|
||||
|
||||
@ -436,6 +441,7 @@ class VLAN(CreatedUpdatedModel, CustomFieldModel):
|
||||
status = models.PositiveSmallIntegerField('Status', choices=VLAN_STATUS_CHOICES, default=1)
|
||||
role = models.ForeignKey('Role', related_name='vlans', on_delete=models.SET_NULL, blank=True, null=True)
|
||||
description = models.CharField(max_length=100, blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
class Meta:
|
||||
ordering = ['site', 'group', 'vid']
|
||||
|
@ -1,5 +1,6 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from extras.api.serializers import CustomFieldsSerializer
|
||||
from tenancy.models import Tenant, TenantGroup
|
||||
|
||||
|
||||
@ -24,12 +25,12 @@ class TenantGroupNestedSerializer(TenantGroupSerializer):
|
||||
# Tenants
|
||||
#
|
||||
|
||||
class TenantSerializer(serializers.ModelSerializer):
|
||||
class TenantSerializer(CustomFieldsSerializer, serializers.ModelSerializer):
|
||||
group = TenantGroupNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Tenant
|
||||
fields = ['id', 'name', 'slug', 'group', 'comments']
|
||||
fields = ['id', 'name', 'slug', 'group', 'comments', 'custom_fields']
|
||||
|
||||
|
||||
class TenantNestedSerializer(TenantSerializer):
|
||||
|
@ -3,6 +3,7 @@ from rest_framework import generics
|
||||
from tenancy.models import Tenant, TenantGroup
|
||||
from tenancy.filters import TenantFilter
|
||||
|
||||
from extras.api.views import CustomFieldModelAPIView
|
||||
from . import serializers
|
||||
|
||||
|
||||
@ -22,18 +23,18 @@ class TenantGroupDetailView(generics.RetrieveAPIView):
|
||||
serializer_class = serializers.TenantGroupSerializer
|
||||
|
||||
|
||||
class TenantListView(generics.ListAPIView):
|
||||
class TenantListView(CustomFieldModelAPIView, generics.ListAPIView):
|
||||
"""
|
||||
List tenants (filterable)
|
||||
"""
|
||||
queryset = Tenant.objects.select_related('group')
|
||||
queryset = Tenant.objects.select_related('group').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.TenantSerializer
|
||||
filter_class = TenantFilter
|
||||
|
||||
|
||||
class TenantDetailView(generics.RetrieveAPIView):
|
||||
class TenantDetailView(CustomFieldModelAPIView, generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single tenant
|
||||
"""
|
||||
queryset = Tenant.objects.select_related('group')
|
||||
queryset = Tenant.objects.select_related('group').prefetch_related('custom_field_values')
|
||||
serializer_class = serializers.TenantSerializer
|
||||
|
@ -1,7 +1,8 @@
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
|
||||
from extras.models import CustomFieldModel
|
||||
from extras.models import CustomFieldModel, CustomFieldValue
|
||||
from utilities.models import CreatedUpdatedModel
|
||||
|
||||
|
||||
@ -32,6 +33,7 @@ class Tenant(CreatedUpdatedModel, CustomFieldModel):
|
||||
group = models.ForeignKey('TenantGroup', related_name='tenants', blank=True, null=True, on_delete=models.SET_NULL)
|
||||
description = models.CharField(max_length=100, blank=True, help_text="Long-form name (optional)")
|
||||
comments = models.TextField(blank=True)
|
||||
custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
|
||||
|
||||
class Meta:
|
||||
ordering = ['group', 'name']
|
||||
|
Loading…
Reference in New Issue
Block a user