1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Adopt django-taggit-serializer for representation of assigned tags in the API

This commit is contained in:
Jeremy Stretch
2018-08-03 09:43:03 -04:00
committed by GitHub
parent ab37264ae1
commit f1bc88fc0c
11 changed files with 66 additions and 77 deletions

View File

@ -7,6 +7,7 @@ django-filter==1.1.0
django-mptt
django-tables2
django-taggit
django-taggit-serializer
django-timezone-field
# https://github.com/encode/django-rest-framework/issues/6053
djangorestframework==3.8.1

View File

@ -1,22 +1,22 @@
from __future__ import unicode_literals
from rest_framework import serializers
from taggit.models import Tag
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
from circuits.constants import CIRCUIT_STATUS_CHOICES
from circuits.models import Provider, Circuit, CircuitTermination, CircuitType
from dcim.api.serializers import NestedSiteSerializer, InterfaceSerializer
from extras.api.customfields import CustomFieldModelSerializer
from tenancy.api.serializers import NestedTenantSerializer
from utilities.api import ChoiceField, TagField, ValidatedModelSerializer, WritableNestedSerializer
from utilities.api import ChoiceField, ValidatedModelSerializer, WritableNestedSerializer
#
# Providers
#
class ProviderSerializer(CustomFieldModelSerializer):
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
class ProviderSerializer(TaggitSerializer, CustomFieldModelSerializer):
tags = TagListSerializerField(required=False)
class Meta:
model = Provider
@ -57,12 +57,12 @@ class NestedCircuitTypeSerializer(WritableNestedSerializer):
# Circuits
#
class CircuitSerializer(CustomFieldModelSerializer):
class CircuitSerializer(TaggitSerializer, CustomFieldModelSerializer):
provider = NestedProviderSerializer()
status = ChoiceField(choices=CIRCUIT_STATUS_CHOICES, required=False)
type = NestedCircuitTypeSerializer()
tenant = NestedTenantSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = Circuit

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
from taggit.models import Tag
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
from circuits.models import Circuit, CircuitTermination
from dcim.constants import (
@ -20,7 +20,7 @@ from ipam.models import IPAddress, VLAN
from tenancy.api.serializers import NestedTenantSerializer
from users.api.serializers import NestedUserSerializer
from utilities.api import (
ChoiceField, SerializedPKRelatedField, TagField, TimeZoneField, ValidatedModelSerializer,
ChoiceField, SerializedPKRelatedField, TimeZoneField, ValidatedModelSerializer,
WritableNestedSerializer,
)
from virtualization.models import Cluster
@ -50,12 +50,12 @@ class RegionSerializer(serializers.ModelSerializer):
# Sites
#
class SiteSerializer(CustomFieldModelSerializer):
class SiteSerializer(TaggitSerializer, CustomFieldModelSerializer):
status = ChoiceField(choices=SITE_STATUS_CHOICES, required=False)
region = NestedRegionSerializer(required=False, allow_null=True)
tenant = NestedTenantSerializer(required=False, allow_null=True)
time_zone = TimeZoneField(required=False)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = Site
@ -118,14 +118,14 @@ class NestedRackRoleSerializer(WritableNestedSerializer):
# Racks
#
class RackSerializer(CustomFieldModelSerializer):
class RackSerializer(TaggitSerializer, CustomFieldModelSerializer):
site = NestedSiteSerializer()
group = NestedRackGroupSerializer(required=False, allow_null=True)
tenant = NestedTenantSerializer(required=False, allow_null=True)
role = NestedRackRoleSerializer(required=False, allow_null=True)
type = ChoiceField(choices=RACK_TYPE_CHOICES, required=False)
width = ChoiceField(choices=RACK_WIDTH_CHOICES, required=False)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = Rack
@ -220,12 +220,12 @@ class NestedManufacturerSerializer(WritableNestedSerializer):
# Device types
#
class DeviceTypeSerializer(CustomFieldModelSerializer):
class DeviceTypeSerializer(TaggitSerializer, CustomFieldModelSerializer):
manufacturer = NestedManufacturerSerializer()
interface_ordering = ChoiceField(choices=IFACE_ORDERING_CHOICES, required=False)
subdevice_role = ChoiceField(choices=SUBDEVICE_ROLE_CHOICES, required=False)
instance_count = serializers.IntegerField(source='instances.count', read_only=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = DeviceType
@ -389,7 +389,7 @@ class DeviceVirtualChassisSerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'master']
class DeviceSerializer(CustomFieldModelSerializer):
class DeviceSerializer(TaggitSerializer, CustomFieldModelSerializer):
device_type = NestedDeviceTypeSerializer()
device_role = NestedDeviceRoleSerializer()
tenant = NestedTenantSerializer(required=False, allow_null=True)
@ -404,7 +404,7 @@ class DeviceSerializer(CustomFieldModelSerializer):
parent_device = serializers.SerializerMethodField()
cluster = NestedClusterSerializer(required=False, allow_null=True)
virtual_chassis = DeviceVirtualChassisSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = Device
@ -459,9 +459,9 @@ class DeviceWithConfigContextSerializer(DeviceSerializer):
# Console server ports
#
class ConsoleServerPortSerializer(ValidatedModelSerializer):
class ConsoleServerPortSerializer(TaggitSerializer, ValidatedModelSerializer):
device = NestedDeviceSerializer()
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = ConsoleServerPort
@ -482,10 +482,10 @@ class NestedConsoleServerPortSerializer(WritableNestedSerializer):
# Console ports
#
class ConsolePortSerializer(ValidatedModelSerializer):
class ConsolePortSerializer(TaggitSerializer, ValidatedModelSerializer):
device = NestedDeviceSerializer()
cs_port = NestedConsoleServerPortSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = ConsolePort
@ -496,9 +496,9 @@ class ConsolePortSerializer(ValidatedModelSerializer):
# Power outlets
#
class PowerOutletSerializer(ValidatedModelSerializer):
class PowerOutletSerializer(TaggitSerializer, ValidatedModelSerializer):
device = NestedDeviceSerializer()
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = PowerOutlet
@ -519,10 +519,10 @@ class NestedPowerOutletSerializer(WritableNestedSerializer):
# Power ports
#
class PowerPortSerializer(ValidatedModelSerializer):
class PowerPortSerializer(TaggitSerializer, ValidatedModelSerializer):
device = NestedDeviceSerializer()
power_outlet = NestedPowerOutletSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = PowerPort
@ -569,7 +569,7 @@ class InterfaceVLANSerializer(WritableNestedSerializer):
fields = ['id', 'url', 'vid', 'name', 'display_name']
class InterfaceSerializer(ValidatedModelSerializer):
class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer):
device = NestedDeviceSerializer()
form_factor = ChoiceField(choices=IFACE_FF_CHOICES, required=False)
lag = NestedInterfaceSerializer(required=False, allow_null=True)
@ -584,7 +584,7 @@ class InterfaceSerializer(ValidatedModelSerializer):
required=False,
many=True
)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = Interface
@ -640,10 +640,10 @@ class InterfaceSerializer(ValidatedModelSerializer):
# Device bays
#
class DeviceBaySerializer(ValidatedModelSerializer):
class DeviceBaySerializer(TaggitSerializer, ValidatedModelSerializer):
device = NestedDeviceSerializer()
installed_device = NestedDeviceSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = DeviceBay
@ -662,12 +662,12 @@ class NestedDeviceBaySerializer(WritableNestedSerializer):
# Inventory items
#
class InventoryItemSerializer(ValidatedModelSerializer):
class InventoryItemSerializer(TaggitSerializer, ValidatedModelSerializer):
device = NestedDeviceSerializer()
# Provide a default value to satisfy UniqueTogetherValidator
parent = serializers.PrimaryKeyRelatedField(queryset=InventoryItem.objects.all(), allow_null=True, default=None)
manufacturer = NestedManufacturerSerializer()
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = InventoryItem
@ -718,9 +718,9 @@ class ContextualInterfaceConnectionSerializer(serializers.ModelSerializer):
# Virtual chassis
#
class VirtualChassisSerializer(ValidatedModelSerializer):
class VirtualChassisSerializer(TaggitSerializer, ValidatedModelSerializer):
master = NestedDeviceSerializer()
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = VirtualChassis

View File

@ -5,7 +5,7 @@ from collections import OrderedDict
from rest_framework import serializers
from rest_framework.reverse import reverse
from rest_framework.validators import UniqueTogetherValidator
from taggit.models import Tag
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
from dcim.api.serializers import NestedDeviceSerializer, InterfaceSerializer, NestedSiteSerializer
from dcim.models import Interface
@ -16,7 +16,7 @@ from ipam.constants import (
from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
from tenancy.api.serializers import NestedTenantSerializer
from utilities.api import (
ChoiceField, SerializedPKRelatedField, TagField, ValidatedModelSerializer, WritableNestedSerializer,
ChoiceField, SerializedPKRelatedField, ValidatedModelSerializer, WritableNestedSerializer,
)
from virtualization.api.serializers import NestedVirtualMachineSerializer
@ -25,9 +25,9 @@ from virtualization.api.serializers import NestedVirtualMachineSerializer
# VRFs
#
class VRFSerializer(CustomFieldModelSerializer):
class VRFSerializer(TaggitSerializer, CustomFieldModelSerializer):
tenant = NestedTenantSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = VRF
@ -87,9 +87,9 @@ class NestedRIRSerializer(WritableNestedSerializer):
# Aggregates
#
class AggregateSerializer(CustomFieldModelSerializer):
class AggregateSerializer(TaggitSerializer, CustomFieldModelSerializer):
rir = NestedRIRSerializer()
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = Aggregate
@ -147,13 +147,13 @@ class NestedVLANGroupSerializer(WritableNestedSerializer):
# VLANs
#
class VLANSerializer(CustomFieldModelSerializer):
class VLANSerializer(TaggitSerializer, CustomFieldModelSerializer):
site = NestedSiteSerializer(required=False, allow_null=True)
group = NestedVLANGroupSerializer(required=False, allow_null=True)
tenant = NestedTenantSerializer(required=False, allow_null=True)
status = ChoiceField(choices=VLAN_STATUS_CHOICES, required=False)
role = NestedRoleSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = VLAN
@ -190,14 +190,14 @@ class NestedVLANSerializer(WritableNestedSerializer):
# Prefixes
#
class PrefixSerializer(CustomFieldModelSerializer):
class PrefixSerializer(TaggitSerializer, CustomFieldModelSerializer):
site = NestedSiteSerializer(required=False, allow_null=True)
vrf = NestedVRFSerializer(required=False, allow_null=True)
tenant = NestedTenantSerializer(required=False, allow_null=True)
vlan = NestedVLANSerializer(required=False, allow_null=True)
status = ChoiceField(choices=PREFIX_STATUS_CHOICES, required=False)
role = NestedRoleSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = Prefix
@ -254,13 +254,13 @@ class IPAddressInterfaceSerializer(serializers.ModelSerializer):
return reverse(url_name, kwargs={'pk': obj.pk}, request=self.context['request'])
class IPAddressSerializer(CustomFieldModelSerializer):
class IPAddressSerializer(TaggitSerializer, CustomFieldModelSerializer):
vrf = NestedVRFSerializer(required=False, allow_null=True)
tenant = NestedTenantSerializer(required=False, allow_null=True)
status = ChoiceField(choices=IPADDRESS_STATUS_CHOICES, required=False)
role = ChoiceField(choices=IPADDRESS_ROLE_CHOICES, required=False)
interface = IPAddressInterfaceSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = IPAddress

View File

@ -144,6 +144,7 @@ INSTALLED_APPS = [
'mptt',
'rest_framework',
'taggit',
'taggit_serializer',
'timezone_field',
'circuits',
'dcim',

View File

@ -2,12 +2,12 @@ from __future__ import unicode_literals
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
from taggit.models import Tag
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
from dcim.api.serializers import NestedDeviceSerializer
from extras.api.customfields import CustomFieldModelSerializer
from secrets.models import Secret, SecretRole
from utilities.api import TagField, ValidatedModelSerializer, WritableNestedSerializer
from utilities.api import ValidatedModelSerializer, WritableNestedSerializer
#
@ -33,11 +33,11 @@ class NestedSecretRoleSerializer(WritableNestedSerializer):
# Secrets
#
class SecretSerializer(CustomFieldModelSerializer):
class SecretSerializer(TaggitSerializer, CustomFieldModelSerializer):
device = NestedDeviceSerializer()
role = NestedSecretRoleSerializer()
plaintext = serializers.CharField()
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = Secret

View File

@ -1,11 +1,11 @@
from __future__ import unicode_literals
from rest_framework import serializers
from taggit.models import Tag
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
from extras.api.customfields import CustomFieldModelSerializer
from tenancy.models import Tenant, TenantGroup
from utilities.api import TagField, ValidatedModelSerializer, WritableNestedSerializer
from utilities.api import ValidatedModelSerializer, WritableNestedSerializer
#
@ -31,9 +31,9 @@ class NestedTenantGroupSerializer(WritableNestedSerializer):
# Tenants
#
class TenantSerializer(CustomFieldModelSerializer):
class TenantSerializer(TaggitSerializer, CustomFieldModelSerializer):
group = NestedTenantGroupSerializer(required=False)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = Tenant

View File

@ -2,7 +2,6 @@ from __future__ import unicode_literals
from collections import OrderedDict
import pytz
from taggit.models import Tag
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
@ -13,7 +12,7 @@ from rest_framework.exceptions import APIException
from rest_framework.permissions import BasePermission
from rest_framework.relations import PrimaryKeyRelatedField
from rest_framework.response import Response
from rest_framework.serializers import Field, ModelSerializer, RelatedField, ValidationError
from rest_framework.serializers import Field, ModelSerializer, ValidationError
from rest_framework.viewsets import ModelViewSet as _ModelViewSet, ViewSet
from .utils import dynamic_import
@ -56,20 +55,6 @@ class IsAuthenticatedOrLoginNotRequired(BasePermission):
# Fields
#
class TagField(RelatedField):
"""
Represent a writable list of Tags associated with an object (use with many=True).
"""
def to_internal_value(self, data):
obj = self.parent.parent.instance
content_type = ContentType.objects.get_for_model(obj)
tag, _ = Tag.objects.get_or_create(content_type=content_type, object_id=obj.pk, name=data)
return tag
def to_representation(self, value):
return value.name
class ChoiceField(Field):
"""
Represent a ChoiceField as {'value': <DB value>, 'label': <string>}.
@ -147,9 +132,10 @@ class ValidatedModelSerializer(ModelSerializer):
"""
def validate(self, data):
# Remove custom field data (if any) prior to model validation
# Remove custom fields data and tags (if any) prior to model validation
attrs = data.copy()
attrs.pop('custom_fields', None)
attrs.pop('tags', None)
# Run clean() on an instance of the model
if self.instance is None:

View File

@ -101,8 +101,8 @@ def serialize_object(obj, extra=None):
}
# Include any tags
if hasattr(obj, 'tags'):
data['tags'] = [tag.name for tag in obj.tags.all()]
# if hasattr(obj, 'tags'):
# data['tags'] = [tag.name for tag in obj.tags.all()]
# Append any extra data
if extra is not None:

View File

@ -1,7 +1,7 @@
from __future__ import unicode_literals
from rest_framework import serializers
from taggit.models import Tag
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
from dcim.api.serializers import NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer
from dcim.constants import IFACE_MODE_CHOICES
@ -9,7 +9,7 @@ from dcim.models import Interface
from extras.api.customfields import CustomFieldModelSerializer
from ipam.models import IPAddress, VLAN
from tenancy.api.serializers import NestedTenantSerializer
from utilities.api import ChoiceField, TagField, ValidatedModelSerializer, WritableNestedSerializer
from utilities.api import ChoiceField, ValidatedModelSerializer, WritableNestedSerializer
from virtualization.constants import VM_STATUS_CHOICES
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
@ -56,11 +56,11 @@ class NestedClusterGroupSerializer(WritableNestedSerializer):
# Clusters
#
class ClusterSerializer(CustomFieldModelSerializer):
class ClusterSerializer(TaggitSerializer, CustomFieldModelSerializer):
type = NestedClusterTypeSerializer()
group = NestedClusterGroupSerializer(required=False, allow_null=True)
site = NestedSiteSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = Cluster
@ -90,7 +90,7 @@ class VirtualMachineIPAddressSerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'family', 'address']
class VirtualMachineSerializer(CustomFieldModelSerializer):
class VirtualMachineSerializer(TaggitSerializer, CustomFieldModelSerializer):
status = ChoiceField(choices=VM_STATUS_CHOICES, required=False)
cluster = NestedClusterSerializer(required=False, allow_null=True)
role = NestedDeviceRoleSerializer(required=False, allow_null=True)
@ -99,7 +99,7 @@ class VirtualMachineSerializer(CustomFieldModelSerializer):
primary_ip = VirtualMachineIPAddressSerializer(read_only=True)
primary_ip4 = VirtualMachineIPAddressSerializer(required=False, allow_null=True)
primary_ip6 = VirtualMachineIPAddressSerializer(required=False, allow_null=True)
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
tags = TagListSerializerField(required=False)
class Meta:
model = VirtualMachine

View File

@ -5,6 +5,7 @@ django-filter==1.1.0
django-mptt==0.9.1
django-tables2==1.21.2
django-taggit==0.22.2
django-taggit-serializer==0.1.7
django-timezone-field==2.1
djangorestframework==3.8.1
drf-yasg[validation]==1.9.1