From 0e04d20762e287c3d6ace41c9c97a58e7bca2117 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 9 Feb 2017 16:55:54 -0500 Subject: [PATCH] Re-implemented CustomFieldSerializer (read-only for now) --- netbox/circuits/api/serializers.py | 12 +++--- netbox/dcim/api/serializers.py | 22 +++++------ netbox/extras/api/serializers.py | 59 ++++++++++++++---------------- netbox/ipam/api/serializers.py | 27 ++++++-------- netbox/tenancy/api/serializers.py | 7 ++-- 5 files changed, 55 insertions(+), 72 deletions(-) diff --git a/netbox/circuits/api/serializers.py b/netbox/circuits/api/serializers.py index b15e735eb..56395547d 100644 --- a/netbox/circuits/api/serializers.py +++ b/netbox/circuits/api/serializers.py @@ -2,7 +2,7 @@ from rest_framework import serializers from circuits.models import Provider, Circuit, CircuitTermination, CircuitType from dcim.api.serializers import NestedSiteSerializer, InterfaceSerializer -from extras.api.serializers import CustomFieldValueSerializer +from extras.api.serializers import CustomFieldModelSerializer from tenancy.api.serializers import NestedTenantSerializer @@ -10,14 +10,13 @@ from tenancy.api.serializers import NestedTenantSerializer # Providers # -class ProviderSerializer(serializers.ModelSerializer): - custom_field_values = CustomFieldValueSerializer(many=True) +class ProviderSerializer(CustomFieldModelSerializer): class Meta: model = Provider fields = [ 'id', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', - 'custom_field_values', + 'custom_fields', ] @@ -61,17 +60,16 @@ class NestedCircuitTypeSerializer(serializers.ModelSerializer): # Circuits # -class CircuitSerializer(serializers.ModelSerializer): +class CircuitSerializer(CustomFieldModelSerializer): provider = NestedProviderSerializer() type = NestedCircuitTypeSerializer() tenant = NestedTenantSerializer() - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: model = Circuit fields = [ 'id', 'cid', 'provider', 'type', 'tenant', 'install_date', 'commit_rate', 'description', 'comments', - 'custom_field_values', + 'custom_fields', ] diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index c2b7bbd81..b4f079281 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -8,7 +8,7 @@ from dcim.models import ( PowerPortTemplate, Rack, RackGroup, RackRole, RACK_FACE_CHOICES, RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHOICES, ) -from extras.api.serializers import CustomFieldValueSerializer +from extras.api.serializers import CustomFieldModelSerializer from tenancy.api.serializers import NestedTenantSerializer from utilities.api import ChoiceFieldSerializer @@ -17,15 +17,14 @@ from utilities.api import ChoiceFieldSerializer # Sites # -class SiteSerializer(serializers.ModelSerializer): +class SiteSerializer(CustomFieldModelSerializer): tenant = NestedTenantSerializer() - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: model = Site fields = [ 'id', 'name', 'slug', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address', 'contact_name', - 'contact_phone', 'contact_email', 'comments', 'custom_field_values', 'count_prefixes', 'count_vlans', + 'contact_phone', 'contact_email', 'comments', 'custom_fields', 'count_prefixes', 'count_vlans', 'count_racks', 'count_devices', 'count_circuits', ] @@ -99,20 +98,19 @@ class NestedRackRoleSerializer(serializers.ModelSerializer): # -class RackSerializer(serializers.ModelSerializer): +class RackSerializer(CustomFieldModelSerializer): site = NestedSiteSerializer() group = NestedRackGroupSerializer() tenant = NestedTenantSerializer() role = NestedRackRoleSerializer() type = ChoiceFieldSerializer(choices=RACK_TYPE_CHOICES) width = ChoiceFieldSerializer(choices=RACK_WIDTH_CHOICES) - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: model = Rack fields = [ 'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'role', 'type', 'width', 'u_height', - 'desc_units', 'comments', 'custom_field_values', + 'desc_units', 'comments', 'custom_fields', ] @@ -157,18 +155,17 @@ class NestedManufacturerSerializer(serializers.ModelSerializer): # Device types # -class DeviceTypeSerializer(serializers.ModelSerializer): +class DeviceTypeSerializer(CustomFieldModelSerializer): manufacturer = NestedManufacturerSerializer() interface_ordering = ChoiceFieldSerializer(choices=IFACE_ORDERING_CHOICES) subdevice_role = ChoiceFieldSerializer(choices=SUBDEVICE_ROLE_CHOICES) instance_count = serializers.IntegerField(source='instances.count', read_only=True) - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: model = DeviceType fields = [ 'id', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'interface_ordering', - 'is_console_server', 'is_pdu', 'is_network_device', 'subdevice_role', 'comments', 'custom_field_values', + 'is_console_server', 'is_pdu', 'is_network_device', 'subdevice_role', 'comments', 'custom_fields', 'instance_count', ] @@ -358,7 +355,7 @@ class DeviceIPAddressSerializer(serializers.ModelSerializer): fields = ['id', 'url', 'family', 'address'] -class DeviceSerializer(serializers.ModelSerializer): +class DeviceSerializer(CustomFieldModelSerializer): device_type = NestedDeviceTypeSerializer() device_role = NestedDeviceRoleSerializer() tenant = NestedTenantSerializer() @@ -370,14 +367,13 @@ class DeviceSerializer(serializers.ModelSerializer): primary_ip4 = DeviceIPAddressSerializer() primary_ip6 = DeviceIPAddressSerializer() parent_device = serializers.SerializerMethodField() - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: 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', 'custom_field_values', + 'comments', 'custom_fields', ] def get_parent_device(self, obj): diff --git a/netbox/extras/api/serializers.py b/netbox/extras/api/serializers.py index 2dec2a360..fa7552dc9 100644 --- a/netbox/extras/api/serializers.py +++ b/netbox/extras/api/serializers.py @@ -1,42 +1,37 @@ +from django.contrib.contenttypes.models import ContentType + from rest_framework import serializers -from extras.models import CF_TYPE_SELECT, CustomFieldChoice, CustomFieldValue, Graph +from extras.models import CustomField, CustomFieldChoice, Graph -# class CustomFieldSerializer(serializers.ModelSerializer): -# """ -# Extends ModelSerializer to render any CustomFields and their values associated with an object. -# """ -# custom_fields = serializers.SerializerMethodField() -# -# def get_custom_fields(self, obj): -# -# # Gather all CustomFields applicable to this object -# 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 -# for cfv in obj.custom_field_values.all(): -# -# # Attempt to suppress database lookups for CustomFieldChoices by using the cached choice set from the view -# # context. -# if cfv.field.type == CF_TYPE_SELECT: -# cfc = { -# 'id': int(cfv.serialized_value), -# 'value': custom_field_choices[int(cfv.serialized_value)] -# } -# fields[cfv.field.name] = CustomFieldChoiceSerializer(instance=cfc).data -# else: -# fields[cfv.field.name] = cfv.value -# -# return fields +class CustomFieldSerializer(serializers.BaseSerializer): + """ + Extends ModelSerializer to render any CustomFields and their values associated with an object. + """ + + def to_representation(self, manager): + + # Initialize custom fields dictionary + data = {f.name: None for f in self.parent._custom_fields} + + # Assign CustomFieldValues from database + for cfv in manager.all(): + data[cfv.field.name] = cfv.value + + return data -class CustomFieldValueSerializer(serializers.ModelSerializer): +class CustomFieldModelSerializer(serializers.ModelSerializer): + custom_fields = CustomFieldSerializer(source='custom_field_values') - class Meta: - model = CustomFieldValue - fields = ['field', 'serialized_value'] + def __init__(self, *args, **kwargs): + + super(CustomFieldModelSerializer, self).__init__(*args, **kwargs) + + # Cache the list of custom fields for this model + content_type = ContentType.objects.get_for_model(self.Meta.model) + self._custom_fields = CustomField.objects.filter(obj_type=content_type) class CustomFieldChoiceSerializer(serializers.ModelSerializer): diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index 86688f82c..75b47b6ca 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -1,7 +1,7 @@ from rest_framework import serializers from dcim.api.serializers import NestedDeviceSerializer, InterfaceSerializer, NestedSiteSerializer -from extras.api.serializers import CustomFieldValueSerializer +from extras.api.serializers import CustomFieldModelSerializer from ipam.models import ( Aggregate, IPAddress, IPADDRESS_STATUS_CHOICES, IP_PROTOCOL_CHOICES, Prefix, PREFIX_STATUS_CHOICES, RIR, Role, Service, VLAN, VLAN_STATUS_CHOICES, VLANGroup, VRF, @@ -14,13 +14,12 @@ from utilities.api import ChoiceFieldSerializer # VRFs # -class VRFSerializer(serializers.ModelSerializer): +class VRFSerializer(CustomFieldModelSerializer): tenant = NestedTenantSerializer() - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: model = VRF - fields = ['id', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'custom_field_values'] + fields = ['id', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'custom_fields'] class NestedVRFSerializer(serializers.ModelSerializer): @@ -80,13 +79,12 @@ class NestedRIRSerializer(serializers.ModelSerializer): # Aggregates # -class AggregateSerializer(serializers.ModelSerializer): +class AggregateSerializer(CustomFieldModelSerializer): rir = NestedRIRSerializer() - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: model = Aggregate - fields = ['id', 'family', 'prefix', 'rir', 'date_added', 'description', 'custom_field_values'] + fields = ['id', 'family', 'prefix', 'rir', 'date_added', 'description', 'custom_fields'] class NestedAggregateSerializer(serializers.ModelSerializer): @@ -135,19 +133,18 @@ class WritableVLANGroupSerializer(serializers.ModelSerializer): # VLANs # -class VLANSerializer(serializers.ModelSerializer): +class VLANSerializer(CustomFieldModelSerializer): site = NestedSiteSerializer() group = NestedVLANGroupSerializer() tenant = NestedTenantSerializer() status = ChoiceFieldSerializer(choices=VLAN_STATUS_CHOICES) role = NestedRoleSerializer() - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: model = VLAN fields = [ 'id', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'display_name', - 'custom_field_values', + 'custom_fields', ] @@ -172,20 +169,19 @@ class WritableVLANSerializer(serializers.ModelSerializer): # Prefixes # -class PrefixSerializer(serializers.ModelSerializer): +class PrefixSerializer(CustomFieldModelSerializer): site = NestedSiteSerializer() vrf = NestedVRFSerializer() tenant = NestedTenantSerializer() vlan = NestedVLANSerializer() status = ChoiceFieldSerializer(choices=PREFIX_STATUS_CHOICES) role = NestedRoleSerializer() - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: model = Prefix fields = [ 'id', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'is_pool', 'description', - 'custom_field_values', + 'custom_fields', ] @@ -210,18 +206,17 @@ class WritablePrefixSerializer(serializers.ModelSerializer): # IP addresses # -class IPAddressSerializer(serializers.ModelSerializer): +class IPAddressSerializer(CustomFieldModelSerializer): vrf = NestedVRFSerializer() tenant = NestedTenantSerializer() status = ChoiceFieldSerializer(choices=IPADDRESS_STATUS_CHOICES) interface = InterfaceSerializer() - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: model = IPAddress fields = [ 'id', 'family', 'address', 'vrf', 'tenant', 'status', 'interface', 'description', 'nat_inside', - 'nat_outside', 'custom_field_values', + 'nat_outside', 'custom_fields', ] diff --git a/netbox/tenancy/api/serializers.py b/netbox/tenancy/api/serializers.py index 46e6edf63..bde86ee28 100644 --- a/netbox/tenancy/api/serializers.py +++ b/netbox/tenancy/api/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from extras.api.serializers import CustomFieldValueSerializer +from extras.api.serializers import CustomFieldModelSerializer from tenancy.models import Tenant, TenantGroup @@ -27,13 +27,12 @@ class NestedTenantGroupSerializer(serializers.ModelSerializer): # Tenants # -class TenantSerializer(serializers.ModelSerializer): +class TenantSerializer(CustomFieldModelSerializer): group = NestedTenantGroupSerializer() - custom_field_values = CustomFieldValueSerializer(many=True) class Meta: model = Tenant - fields = ['id', 'name', 'slug', 'group', 'description', 'comments', 'custom_field_values'] + fields = ['id', 'name', 'slug', 'group', 'description', 'comments', 'custom_fields'] class NestedTenantSerializer(serializers.ModelSerializer):