Coverage for extras/api/serializers_/customfields.py: 58%
52 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django.utils.translation import gettext as _
2from drf_spectacular.types import OpenApiTypes
3from drf_spectacular.utils import extend_schema_field
4from rest_framework import serializers
6from core.models import ObjectType
7from extras.choices import *
8from extras.models import CustomField, CustomFieldChoiceSet
9from netbox.api.fields import ChoiceField, ContentTypeField
10from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
11from users.api.serializers_.mixins import OwnerMixin
13__all__ = (
14 'CustomFieldChoiceSetSerializer',
15 'CustomFieldSerializer',
16)
19class CustomFieldChoiceSetSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
20 base_choices = ChoiceField(
21 choices=CustomFieldChoiceSetBaseChoices,
22 required=False,
23 allow_null=True,
24 )
25 extra_choices = serializers.ListField(
26 child=serializers.ListField(
27 min_length=2,
28 max_length=2
29 )
30 )
31 choice_colors = serializers.DictField(
32 child=serializers.ChoiceField(choices=CustomFieldChoiceColorChoices),
33 required=False,
34 )
35 choices_count = serializers.IntegerField(read_only=True)
37 class Meta:
38 model = CustomFieldChoiceSet
39 fields = [
40 'id', 'url', 'display_url', 'display', 'name', 'description', 'base_choices', 'extra_choices',
41 'choice_colors', 'order_alphabetically', 'choices_count', 'owner', 'created', 'last_updated',
42 ]
43 brief_fields = ('id', 'url', 'display', 'name', 'description', 'choices_count')
46class CustomFieldSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
47 object_types = ContentTypeField(
48 queryset=ObjectType.objects.with_feature('custom_fields'),
49 many=True
50 )
51 type = ChoiceField(choices=CustomFieldTypeChoices)
52 related_object_type = ContentTypeField(
53 queryset=ObjectType.objects.all(),
54 required=False,
55 allow_null=True
56 )
57 filter_logic = ChoiceField(choices=CustomFieldFilterLogicChoices, required=False)
58 data_type = serializers.SerializerMethodField()
59 choice_set = CustomFieldChoiceSetSerializer(
60 nested=True,
61 required=False,
62 allow_null=True
63 )
64 ui_visible = ChoiceField(choices=CustomFieldUIVisibleChoices, required=False)
65 ui_editable = ChoiceField(choices=CustomFieldUIEditableChoices, required=False)
66 # A field is live only while active; the remaining states report a pending bulk update of its
67 # stored data. Read-only: the state is driven by the responsible background job.
68 status = ChoiceField(choices=CustomFieldStatusChoices, read_only=True)
70 class Meta:
71 model = CustomField
72 fields = [
73 'id', 'url', 'display_url', 'display', 'object_types', 'type', 'related_object_type', 'data_type',
74 'name', 'label', 'group_name', 'description', 'required', 'unique', 'search_weight', 'filter_logic',
75 'ui_visible', 'ui_editable', 'is_cloneable', 'nulls_first', 'default', 'related_object_filter', 'weight',
76 'validation_minimum', 'validation_maximum', 'validation_regex', 'validation_schema', 'choice_set',
77 'status', 'owner', 'comments', 'created', 'last_updated',
78 ]
79 brief_fields = ('id', 'url', 'display', 'name', 'description')
81 def validate_type(self, value):
82 if self.instance and self.instance.type != value:
83 raise serializers.ValidationError(_('Changing the type of custom fields is not supported.'))
85 return value
87 @extend_schema_field(OpenApiTypes.STR)
88 def get_data_type(self, obj):
89 types = CustomFieldTypeChoices
90 if obj.type == types.TYPE_INTEGER:
91 return 'integer'
92 if obj.type == types.TYPE_DECIMAL:
93 return 'decimal'
94 if obj.type == types.TYPE_BOOLEAN:
95 return 'boolean'
96 if obj.type in (types.TYPE_JSON, types.TYPE_OBJECT):
97 return 'object'
98 if obj.type in (types.TYPE_MULTISELECT, types.TYPE_MULTIOBJECT):
99 return 'array'
100 return 'string'