diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 4c65a3a19..d8bf68e12 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -1,3 +1,4 @@ +from django.contrib.contenttypes.models import ContentType from rest_framework import serializers from rest_framework.validators import UniqueTogetherValidator from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField @@ -502,8 +503,12 @@ class InventoryItemSerializer(TaggitSerializer, ValidatedModelSerializer): # class CableSerializer(ValidatedModelSerializer): - termination_a_type = ContentTypeField() - termination_b_type = ContentTypeField() + termination_a_type = ContentTypeField( + queryset=ContentType.objects.filter(model__in=CABLE_TERMINATION_TYPES) + ) + termination_b_type = ContentTypeField( + queryset=ContentType.objects.filter(model__in=CABLE_TERMINATION_TYPES) + ) termination_a = serializers.SerializerMethodField(read_only=True) termination_b = serializers.SerializerMethodField(read_only=True) status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, required=False) diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 8fddc7129..2fd398f08 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -1,7 +1,7 @@ from collections import OrderedDict from django.conf import settings -from django.db.models import F, Q +from django.db.models import F from django.http import HttpResponseForbidden from django.shortcuts import get_object_or_404 from drf_yasg import openapi diff --git a/netbox/extras/api/serializers.py b/netbox/extras/api/serializers.py index 7643562bb..88de52929 100644 --- a/netbox/extras/api/serializers.py +++ b/netbox/extras/api/serializers.py @@ -1,3 +1,4 @@ +from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from rest_framework import serializers from taggit.models import Tag @@ -88,7 +89,9 @@ class TagSerializer(ValidatedModelSerializer): # class ImageAttachmentSerializer(ValidatedModelSerializer): - content_type = ContentTypeField() + content_type = ContentTypeField( + queryset=ContentType.objects.all() + ) parent = serializers.SerializerMethodField(read_only=True) class Meta: diff --git a/netbox/extras/api/views.py b/netbox/extras/api/views.py index 0453b1f1c..3fcb14920 100644 --- a/netbox/extras/api/views.py +++ b/netbox/extras/api/views.py @@ -23,7 +23,6 @@ from . import serializers class ExtrasFieldChoicesViewSet(FieldChoicesViewSet): fields = ( - (CustomField, ['type']), (Graph, ['type']), ) diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index 030266188..9b2c45371 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -128,6 +128,7 @@ class VLANSerializer(TaggitSerializer, CustomFieldModelSerializer): # class PrefixSerializer(TaggitSerializer, CustomFieldModelSerializer): + family = ChoiceField(choices=AF_CHOICES, read_only=True) site = NestedSiteSerializer(required=False, allow_null=True) vrf = NestedVRFSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True) @@ -189,6 +190,7 @@ class IPAddressInterfaceSerializer(WritableNestedSerializer): class IPAddressSerializer(TaggitSerializer, CustomFieldModelSerializer): + family = ChoiceField(choices=AF_CHOICES, read_only=True) vrf = NestedVRFSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True) status = ChoiceField(choices=IPADDRESS_STATUS_CHOICES, required=False) diff --git a/netbox/utilities/api.py b/netbox/utilities/api.py index b65a7841b..e0e7f3c71 100644 --- a/netbox/utilities/api.py +++ b/netbox/utilities/api.py @@ -32,7 +32,9 @@ def get_serializer_for_model(model, prefix=''): try: return dynamic_import(serializer_name) except AttributeError: - return None + raise Exception( + "Could not determine serializer for {}.{} with prefix '{}'".format(app_name, model_name, prefix) + ) # @@ -100,6 +102,10 @@ class ChoiceField(Field): return data + @property + def choices(self): + return self._choices + class ContentTypeField(RelatedField): """ @@ -110,10 +116,6 @@ class ContentTypeField(RelatedField): "invalid": "Invalid value. Specify a content type as '.'.", } - # Can't set this as an attribute because it raises an exception when the field is read-only - def get_queryset(self): - return ContentType.objects.all() - def to_internal_value(self, data): try: app_label, model = data.split('.') @@ -256,10 +258,14 @@ class FieldChoicesViewSet(ViewSet): self._fields = OrderedDict() for cls, field_list in self.fields: for field_name in field_list: + model_name = cls._meta.verbose_name.lower().replace(' ', '-') key = ':'.join([model_name, field_name]) + + serializer = get_serializer_for_model(cls)() choices = [] - for k, v in cls._meta.get_field(field_name).choices: + + for k, v in serializer.get_fields()[field_name].choices.items(): if type(v) in [list, tuple]: for k2, v2 in v: choices.append({